Fork me on GitHub

数据结构与算法——栈 迷宫算法 回溯法

 

 

找迷宫通路需要使用回溯法,找迷宫通路是对回溯法的一个很好的应用,实现回溯的过程用到数据结构—

 

回溯法:对一个包括有很多个结点,每个结点有若干个搜索分支的问题,把原问题分解为若干个子问题求解的 算法;当搜索到某个结点发现无法再继续搜索下去时,就让搜索过程回溯(回退)到该节点的前一个结点,继续 搜索该节点外的其他尚未搜索的分支;如果发现该结点无法再搜索下去,就让搜索过程回溯到这个结点的前一 结点继续这样的搜索过程;这样的搜索过程一直进行到搜索到问题的解或者搜索完了全部可搜索分支没有解存 在为止。

 

代码实现

maze.h

 1 #pragma once
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 
 5 #define MAXSIZE 100                    //预先分配空间,这个数值根据实际需要预估确定
 6 
 7 //存储坐标的结构体  _x; _y;
 8 typedef struct _Position            
 9 {
10     int _x;
11     int _y;
12 }Position;
13 
14 typedef Position ElemType;            //栈中存储的类型 Position 存储坐标的结构体  _x; _y;
15 
16 //栈 包含栈顶与栈底指针
17 typedef struct _SqStack
18 {
19     ElemType* base = NULL;                   //栈底指针
20     ElemType* top = NULL;                    //栈顶指针
21 }SqStack;
22 
23 //构造一个空栈
24 bool InitStack(SqStack& S)            
25 {
26     S.base = new ElemType[MAXSIZE];     //为顺序栈分配一个最大容量为 MAXSIZE 的空间
27     if (!S.base)                        //空间分配失败
28         return false;
29     S.top = S.base;                     //top 初始为 base,空栈
30 
31     return true;
32 }
33 
34 // 插入元素 e 为新的栈顶元素
35 bool PushStack(SqStack &S, ElemType e)    
36 {
37     if (S.top - S.base == MAXSIZE)            //栈满
38         return false;  
39 
40     *(S.top++) = e;                        //元素 e 压入栈顶,然后栈顶指针加 1,等价于*S.top=e; S.top++;
41 
42     return true;
43 }
44 
45 //删除 S 的栈顶元素,暂存在变量 e 中
46 bool PopStack(SqStack& S, ElemType& e) 
47 {
48     if (S.base == S.top)                //栈空
49     {
50         return false;
51     }
52     e = *(--S.top);                        //栈顶指针减 1,将栈顶元素赋给 e
53 
54     return true;
55 }
56 
57 //返回 S 的栈顶元素,栈顶指针不变
58 ElemType* GetTop(SqStack& S)            
59 {
60     if (S.top != S.base)                //栈非空
61     {
62         return S.top - 1;                //返回栈顶元素的值,栈顶指针不变
63     }
64     else
65     {
66         return NULL;
67     }
68 }
69 
70 //返回栈中元素个数
71 int GetSize(SqStack& S)                    
72 {
73     return (S.top - S.base);
74 }
75 
76 //判断栈是否为空
77 bool IsEmpty(SqStack& S)                
78 {
79     if (S.top == S.base)
80     {
81         return true;
82     }
83     else
84     {
85         return false;
86     }
87 }
88 
89 //销毁栈
90 void DestoryStack(SqStack& S)            
91 {
92     if (S.base)
93     {
94         free(S.base);
95         S.base = NULL;
96         S.top = NULL;
97     }
98 }

 

 

maze.cpp

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include "maze.h"
  5 #include <assert.h>
  6 
  7 #define ROW 6       //坐标系宽度
  8 #define COL 6       //坐标系高度
  9 
 10 //储存迷宫地图
 11 typedef struct _Maze        
 12 {
 13     int map[ROW][COL];
 14 }Maze;
 15 
 16 //迷宫的初始化
 17 void InitMaze(Maze* m, int map[ROW][COL])
 18 {
 19     if (m == NULL || map == NULL)
 20         return;
 21 
 22     for (int i = 0; i < ROW; ++i)
 23     {
 24         for (int j = 0; j < COL; ++j)
 25         {
 26             m->map[i][j] = map[i][j];
 27         }
 28     }
 29 }
 30 
 31 void PrintMaze(Maze* m)                               //打印迷宫
 32 {
 33     for (int i = 0; i < ROW; ++i)
 34     {
 35         for (int j = 0; j < COL; ++j)
 36         {
 37             printf("%d ", m->map[i][j]);
 38         }
 39         printf("\n");
 40     }
 41     printf("\n");
 42 }
 43 
 44 //判断是否是有效的入口
 45 int IsValidEnter(Maze* m, Position cur)
 46 {
 47     assert(m);
 48 
 49     if ((cur._x == 0 || cur._x == ROW - 1) || (cur._y == 0 || cur._y == COL - 1) && (m->map[cur._x][cur._y] == 1))
 50         return 1;
 51     else
 52         return 0;
 53 }
 54 
 55 //判断当前节点的下一个节点能否走通
 56 int IsNextPass(Maze* m, Position cur, Position next) 
 57 {
 58     assert(m);
 59     //判断 next 节点是否为 cur 的下一节点
 60     if (
 61         ((next._x == cur._x) && ((next._y == cur._y + 1) || (next._y == cur._y - 1)))         //在同一行上并且相邻
 62         ||
 63         ((next._y == cur._y) && ((next._x == cur._x + 1) || (next._x == cur._x - 1)))         //或在同一列上并且相邻
 64         )        
 65     {
 66         //判断下一个节点是否在迷宫里面
 67         if (((next._x >= 0 && next._x < ROW) || (next._y >= 0 && next._y < COL)) && (m->map[next._x][next._y] == 1))
 68         {
 69             return 1;
 70         }
 71     }
 72     return 0;
 73 }
 74 
 75 //判断当前节点是不是有效的迷宫出口
 76 int IsValidExit(Maze* m, Position cur, Position enter) 
 77 {
 78     assert(m);
 79     //这里首先得保证该节点不是入口点,其次只要它处在迷宫的边界即可
 80     if ((cur._x != enter._x || cur._y != enter._y) && ((cur._x == 0 || cur._x == ROW - 1) || (cur._y == 0 || cur._y == COL - 1)))
 81         return 1;
 82     else
 83         return 0;
 84 }
 85 
 86 //找迷宫通路 Maze* m 地图, Position enter入口, SqStack* s 栈空间
 87 int PassMaze(Maze* m, Position enter, SqStack* s)                     
 88 {
 89     assert(m && IsValidEnter(m, enter) == 1);                        //对给的迷宫的入口进行合法性判断
 90     
 91     Position cur = enter;                                           //当前判断坐标
 92     Position next;
 93     PushStack(*s, cur);                                             //首先将迷宫的入口压入栈中
 94     m->map[cur._x][cur._y] = 2;                                     //将入口值改为 2
 95 
 96     //PrintMaze(m);
 97     while (!IsEmpty(*s))
 98     {
 99         cur = *GetTop(*s);
100         //printf("cur: %d %d\n",cur._x, cur._y);
101         if (IsValidExit(m, cur, enter) == 1)                           //判断当前位置是否出口
102             return 1;
103 
104         //尝试向左一步:看当前节点的左一个节点能不能走通
105         next = cur;
106         next._y = cur._y - 1;
107         if (IsNextPass(m, cur, next) == 1)
108         {
109             PushStack(*s, next);
110             m->map[next._x][next._y] = m->map[cur._x][cur._y] + 1;
111             //PrintMaze(m);
112             continue;
113         }
114 
115         //尝试向上一步:看当前节点的上一个节点能不能走通
116         next = cur;
117         next._x = cur._x - 1;
118         if (IsNextPass(m, cur, next) == 1)                            //next 节点能够走通时,将其压入栈中
119         {
120             PushStack(*s, next);
121             m->map[next._x][next._y] = m->map[cur._x][cur._y] + 1;    //将 next 节点的值等于 cur 节点的值加 1
122             //PrintMaze(m);
123             continue;
124         }
125 
126         //右:看当前节点的向右的一个节点能不能走通
127         next = cur;
128         next._y = cur._y + 1;
129         if (IsNextPass(m, cur, next) == 1)
130         {
131             PushStack(*s, next);
132             m->map[next._x][next._y] = m->map[cur._x][cur._y] + 1;
133             //PrintMaze(m);
134             continue;
135         }
136 
137         //下:看当前节点的下一个节点能不能走通
138         next = cur;
139         next._x = cur._x + 1;
140         if (IsNextPass(m, cur, next) == 1)
141         {
142             PushStack(*s, next);
143             m->map[next._x][next._y] = m->map[cur._x][cur._y] + 1;
144             //PrintMaze(m);
145             continue;
146         }
147 
148         //走到这里说明当前节点的四个方向都走不通,进行回溯,看前一个节点未被遍历的方向是否还能走通
149         Position tmp;
150         PopStack(*s, tmp);
151     }
152     return 0;
153 }
154 int main()
155 {
156     //用二维数组描绘迷宫:1 代表通路,0 代表墙
157     int map[ROW][COL] =
158     {
159         0,0,1,0,0,0,
160         0,0,1,1,1,0,
161         0,0,1,0,0,0,
162         0,1,1,1,1,0,
163         0,0,1,0,1,0,
164         0,0,0,0,1,0
165     };
166 
167     Maze m;                                 //迷宫地图
168     ElemType enter;                         //迷宫入口
169     enter._x = 0;
170     enter._y = 2;
171 
172     InitMaze(&m, map);                      
173     PrintMaze(&m);
174 
175     //system("pause");
176     //exit(0);
177 
178     SqStack s;                              //定义栈,保存已走过的坐标轨迹,便于回溯
179     InitStack(s);                           //栈的初始
180     int ret = PassMaze(&m, enter, &s);      //使用栈和回溯法解开迷宫
181     if (ret)
182     {
183         printf("恭喜你!终于找到了出口~\n");
184     }
185     else
186     {
187         printf("不是我笨!实在没有出口~\n");
188     }
189 
190     PrintMaze(&m);
191     system("pause");
192 
193     return 0;
194 }

 

posted @ 2020-10-22 11:39  索智源  阅读(379)  评论(0编辑  收藏  举报