迷宫算法及数据结构分析(by WIzaRD_ssc)
2015-07-23 16:55
1031 查看
关于迷宫,承载着我们童年中的点滴记忆。当然,那时候总有些迷宫册子,每本还有专门的主题(奥特曼,葫芦娃,铠甲勇士什么的= =)。而且不得不说,真是干一行爱一行,这些出册子的人,把迷宫这个游戏可是上升到了一个高度。就比如说什么“碰见怪兽了要折返”什么的。
以上基于我们的童年,更基于那些“伟大的”迷宫设计设计师们。但是,在计算机行业领域中,我们更看重数据,以及对数据的运算和处理。所以 解决迷宫问题 就成了初学者对计算机编程技术及思想的一次质的飞跃。
好,废话不多说,接下来,我将从对迷宫算法的分析,数据结构的选择,及程序的实现进行简略描述。
在计算机中,为了着重数据操作,我忽略掉了类似立交桥般复杂的线路,以及小怪兽的设定等。
如图左上角空白(#为边界,空白即指无字符的地方)为起点,右下角为终点。此迷宫中最需要我们想到的该是有岔道,还有圈。
也就是说程序应当有排除岔道,还有排除圈的能力。对于排除岔道,只要判断当前位置对于行迷宫者来说是否为#即可,而对于圈,我们可以用一个mark数组来标记此位置是否走过,每当向下一个位置走时就同时判断是否为#和此位置是否走过即可(这两个判断在下文直接简称为“通路成立判断”)。
以上仅解决了两个小问题,而更重要的是:行迷宫者到底如何走,是让它一直向上走,还是一直向右走,还是转着圈走。当我们在想它如何走时,方法就出现了。我们可以记录当前坐标值,然后对周围四个方向,即上,下,左,右依次进行“通路成立判断”,如果成立,按成立的那个方向移动一格,并再次让程序进行周围四个方向,即上,下,左,右依次进行“通路成立判断”。当四个方向的“通路成立判断”都不成立,那么就知道此路不通,接着让行迷宫者按原路返回,并继续进行没有判断完的方向(例如,某个位置向左可以走,但移动后发现四个方向的“通路成立判断”都不成立,那么此时倒退回去,并接着进行右的“通路成立判断”(因为判断顺序为上,下,左,右))就这样,让程序不断地做此种循环,直到当前坐标值等于终点坐标值。
但是,我们的目的是为了让程序求显示出求解过程,以上只是让行迷宫者走到了终点,而并没有记录他的行迹。接下来,我对存储路径的数据结构的选择进行描述。
栈是后进先出的线性数据结构,当每走一格时,就对上一格的坐标和向下一格要走的方向进行记录(即遵从:当前坐标+方向=下一格要走的坐标=路径描述)。并规定每当遇到死路,即四个方向的“通路成立判断”都不成立时,从栈中取出栈顶元素(因为栈顶恰好是上一步的路径描述)。就这样到当前坐标值等于终点坐标值时,及循环停止时,栈中的所有元素自下而上就是对路径的全部描述。
紧接着,可以根据算法与数据结构编出程序来,下面就是程序的实现。
以上基于我们的童年,更基于那些“伟大的”迷宫设计设计师们。但是,在计算机行业领域中,我们更看重数据,以及对数据的运算和处理。所以 解决迷宫问题 就成了初学者对计算机编程技术及思想的一次质的飞跃。
好,废话不多说,接下来,我将从对迷宫算法的分析,数据结构的选择,及程序的实现进行简略描述。
1)迷宫算法的分析:
在计算机中,为了着重数据操作,我忽略掉了类似立交桥般复杂的线路,以及小怪兽的设定等。
如图左上角空白(#为边界,空白即指无字符的地方)为起点,右下角为终点。此迷宫中最需要我们想到的该是有岔道,还有圈。
也就是说程序应当有排除岔道,还有排除圈的能力。对于排除岔道,只要判断当前位置对于行迷宫者来说是否为#即可,而对于圈,我们可以用一个mark数组来标记此位置是否走过,每当向下一个位置走时就同时判断是否为#和此位置是否走过即可(这两个判断在下文直接简称为“通路成立判断”)。
以上仅解决了两个小问题,而更重要的是:行迷宫者到底如何走,是让它一直向上走,还是一直向右走,还是转着圈走。当我们在想它如何走时,方法就出现了。我们可以记录当前坐标值,然后对周围四个方向,即上,下,左,右依次进行“通路成立判断”,如果成立,按成立的那个方向移动一格,并再次让程序进行周围四个方向,即上,下,左,右依次进行“通路成立判断”。当四个方向的“通路成立判断”都不成立,那么就知道此路不通,接着让行迷宫者按原路返回,并继续进行没有判断完的方向(例如,某个位置向左可以走,但移动后发现四个方向的“通路成立判断”都不成立,那么此时倒退回去,并接着进行右的“通路成立判断”(因为判断顺序为上,下,左,右))就这样,让程序不断地做此种循环,直到当前坐标值等于终点坐标值。
但是,我们的目的是为了让程序求显示出求解过程,以上只是让行迷宫者走到了终点,而并没有记录他的行迹。接下来,我对存储路径的数据结构的选择进行描述。
2)数据结构的选择
栈是后进先出的线性数据结构,当每走一格时,就对上一格的坐标和向下一格要走的方向进行记录(即遵从:当前坐标+方向=下一格要走的坐标=路径描述)。并规定每当遇到死路,即四个方向的“通路成立判断”都不成立时,从栈中取出栈顶元素(因为栈顶恰好是上一步的路径描述)。就这样到当前坐标值等于终点坐标值时,及循环停止时,栈中的所有元素自下而上就是对路径的全部描述。
紧接着,可以根据算法与数据结构编出程序来,下面就是程序的实现。
3)程序的实现
#include<iostream> #include<cstdlib> #define Max_Size 100 using namespace std; enum Direcation { Up = 1, Down = 2, Left = 3, Right = 4 }; typedef struct { int x, y; }Coordinate; typedef struct { Coordinate coord; Direcation direcation; }Node; class Stack { public: Stack(); bool IsEmpty() const; bool IsTopful() const; bool Push(Node Pushed); bool Pop(); const Node& GetTop() const; void Output() const; private: Node stack[Max_Size]; unsigned int top; }; void Check(const bool MAZE[][10], bool MARK[][10], Stack &wizard, Coordinate coord); void OutputMaze(const bool MAZE[][10]); const Coordinate Origin = { 1, 1 }, Terminal = { 8, 8 }; int main() { Stack wizard; Coordinate coord = Origin; bool MAZE[10][10]={ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 1, 1, 0, 1}, {1, 0, 1, 0, 1, 0, 0, 1, 0, 1}, {1, 0, 1, 0, 0, 0, 1, 0, 0, 1}, {1, 0, 1, 1, 1, 0, 0, 0, 1, 1}, {1, 0, 1, 0, 1, 1, 1, 1, 1, 1}, {1, 0, 1, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 1, 0, 1, 0, 1, 1, 0, 1}, {1, 0, 0, 0, 1, 0, 0, 1, 0, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; bool MARK[10][10] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, }; Check(MAZE, MARK, wizard, coord); OutputMaze(MAZE); wizard.Output(); cout << "9,9 !\n\n"; system("pause"); return 0; } void Check(const bool MAZE[][10], bool MARK[][10], Stack &wizard, Coordinate coord) { Node now; MARK[coord.x][coord.y] = false;//mark if (MARK[coord.x - 1][coord.y] && MAZE[coord.x - 1][coord.y] == 0)//up { if (coord.x == Terminal.x&&coord.y == Terminal.y) return;//1.check true or false now.coord = coord; now.direcation = Up;//2.unload wizard.Push(now);//3.push to stack; coord.x--;//4.change moveable coordinate Check(MAZE, MARK, wizard, coord);//5.provide the coordinate at present } else if (MARK[coord.x][coord.y - 1] && MAZE[coord.x][coord.y - 1] == 0)//left { if (coord.x == Terminal.x&&coord.y == Terminal.y) return; now.coord = coord; now.direcation = Left; wizard.Push(now); coord.y--; Check(MAZE, MARK, wizard, coord); } else if (MARK[coord.x][coord.y + 1] && MAZE[coord.x][coord.y + 1] == 0)//right { if (coord.x == Terminal.x&&coord.y == Terminal.y) return; now.coord = coord; now.direcation = Right; wizard.Push(now); coord.y++; Check(MAZE, MARK, wizard, coord); } else if (MARK[coord.x + 1][coord.y] && MAZE[coord.x + 1][coord.y] == 0)//down { if (coord.x == Terminal.x&&coord.y == Terminal.y) return; now.coord = coord; now.direcation = Down; wizard.Push(now); coord.x++; Check(MAZE, MARK, wizard, coord); } else { if (coord.x == Terminal.x&&coord.y == Terminal.y) return;//1.check true or false coord = wizard.GetTop().coord;//2.change moveable coordinate wizard.Pop();//3.delete Check(MAZE, MARK, wizard, coord);//4.provide the coordinate at present } return; } void OutputMaze(const bool MAZE[][10]) 4000 { for (int inset = 0; inset < 10; inset++) { for (int inset1 = 0; inset1 < 10; inset1++) { if (MAZE[inset][inset1]) cout << "# "; else cout << " "; } cout << endl; } cout << endl; } Stack::Stack() { top = 0; } bool Stack::IsEmpty() const { return (top == 0); } bool Stack::IsTopful() const { return (top == Max_Size + 1); } bool Stack::Push(Node Pushed) { if (IsTopful()) return false; else { stack[top] = Pushed; top++; return true; } } bool Stack::Pop() { if (IsEmpty()) return false; else { top--; return true; } } const Node& Stack::GetTop() const { return stack[top - 1]; } void Stack::Output() const { for (unsigned int inset = 0; inset < top; inset++) { cout << stack[inset].coord.x + 1 << ',' << stack[inset].coord.y + 1 << " "; switch (stack[inset].direcation) { case Up:cout << "Up"; break; case Down:cout << "Down"; break; case Left:cout << "Left"; break; case Right:cout << "Right"; break; default:cout << "Unknow"; } cout << endl; } cout << endl; return; }以及程序的输出:
by WIzaRD_ssc
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- Lua教程(七):数据结构详解
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- C#数据结构揭秘一
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- C++基于栈实现铁轨问题
- c语言实现的带通配符匹配算法
- 数据结构之Treap详解
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法