数据结构试验二 老鼠走迷宫
- 实验思路:
用深度优先搜索实现,使用堆栈存储老鼠走过的路径。最终实现最短路径的的求解。
我用一个二维数组map[10][12]来表示地图。其元素有三种取值:0代表无墙、没走过;1代表墙;2代表无墙、已走过。
首先输入start点坐标(即为其在数中的行列坐标),若输入不合法(越界,或start在墙中)则需重新输入。
1.先判断start是否有后继。这里我做的比较繁琐,是把每种情况都判断了。其实可以在地图外再包一层墙,这样就可以所有点用一种方式来判断了。
若start点无问题,则把它压入栈s。
- 定义一个栈minPath用来存放最短路径
- 用FillStack函数填充s。若失败则无出口。
- 若填充成功,判断路径长度。若为2,则已经是最短路径,直接输出。
- 若其它情况,则先把s的内容赋给minPath作为起始最小路径,对s修改方向后再进行填充。若填充后的路径更小,则更新minPath。重复上述操作直至遍历全部路径。
- 释放空间
具体细节见注释
- 心得:
- 堆栈不能直接复制,比如s1 = s2这样。要用一个额外的栈,把s2的内容输出到额外栈,额外栈此时倒序存放复制的内容,再将额外栈输出到s1和s2(注意这里也要输出到s2,否则s2就是空的了)。
- 用栈来代表路径。栈中元素就是地图上的一个点
- 我觉得我做的比较好的一个地方是提炼了FillStack和RidirectStack这两个函数。
FillStack的起始条件是一条路径,然后这个函数它会填充这条路径,如果能找到出口,则返回true,如果找不到出口,则返回false。
RidirectStack的作用是修改路径。起始条件是一条路径,它拿出路径的最后一个节点,并修改最后一个节点的方向。如果这个节点不能再进行修改了,则删除该点,再倒数第二个,修改方向.....依次直到拿出了起始点。如果起始点也不能修改方向了,则是空栈。
这个函数还是比较关键的,在填充路径和求取最小路径时都有用到
4.在FillStack里用dowhile循环是因为,循环截止的条件start点也可能满足,所以要先执行一次。
5.地图上的点需要有三种表示:有墙,无墙走过,无墙没走过。如果没有标记已经走过的路径,当地图有形如:
1 1 0 0 0 0 0 1
1 1 0 1 1 1 0 1
1 1 0 0 0 0 0 1
这样的圈时,就停不下来了。
6.很多地方各种边界条件都要卡(比如判断下一个点的方向时,回退修改路径时等等),有时候一个地方忘记限制了(比如没卡数组边界,起始点要单独拿出来讨论)程序就跑半天跑不完了*崩溃*。还是要细致一点。
#include <iostream>
enum direction {
UP, RIGHT, DOWN, LEFT
};
typedef struct {
int x;
int y;
enum direction dir;
} Elem;
typedef struct Node {
Elem data;
struct Node *next;
} Node;
typedef Node *Stack;
void InitStack(Stack *s) {
*s = (Node *) malloc(sizeof(Node));
(*s)->next = nullptr;
}
bool StackEmpty(Stack s) {
if (s->next == nullptr)
return true;
else
return false;
}
void Push(Stack s, Elem e) {
Node *t = (Node *) malloc(sizeof(Node));
t->data = e;
t->next = s->next;
s->next = t;
}
void Pop(Stack s) {
if (StackEmpty(s))
return;
Node *t = s->next;
s->next = t->next;
free(t);
}
Elem Top(Stack s) {
return s->next->data;
}
void DeleteStack(Stack s) {
while (s != nullptr) {
Node *t = s;
s = s->next;
free(t);
}
}
void ClearStack(Stack s) {
while (!StackEmpty(s)) {
Pop(s);
}
}
int getStackLength(Stack s) {
int num = 0;
while (s->next != nullptr) {
num += 1;
s = s->next;
}
return num;
}
void PrintStack(Stack s) {
Stack t;
InitStack(&t);
Elem temp_elem;
while (!StackEmpty(s)) {
temp_elem = Top(s);
Pop(s);
Push(t, temp_elem);
}
printf("START--");
while (!StackEmpty(t)) {
//
temp_elem = Top(t);
switch (temp_elem.dir) {
case UP:
printf("UP");
break;
case RIGHT:
printf("RIGHT");
break;
case DOWN:
printf("DOWN");
break;
case LEFT:
printf("LEFT");
break;
}
temp_elem = Top(t);
Pop(t);
Push(s, temp_elem);
printf("--");
}
printf("Export");
}
void CopyStack(Stack s1, Stack s2) {
Stack temp;
InitStack(&temp);
Elem elem;
while (!StackEmpty(s2)) {
elem = Top(s2);
Pop(s2);
Push(temp, elem);
}
Elem t;
while (!StackEmpty(temp)) {
elem = Top(temp);
t = elem;
Pop(temp);
Push(s1, elem);
Push(s2, t);
}
}
int map[10][12] = {{1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1},
{1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1},
{1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1},
{1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1},
{1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1},
{1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1},
{1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1}};
void RedirectStack(Stack s) {
bool flag_stop = false;
Elem top, next;
while (!StackEmpty(s) && !flag_stop) {
top = Top(s);
Pop(s);
if (StackEmpty(s)) {
switch (top.dir) {
case UP:
if (top.y != 11 && !map[top.x][top.y + 1]) {
top.dir = RIGHT;
Push(s, top);
flag_stop = true;
} else if (top.x != 9 && !map[top.x + 1][top.y]) {
top.dir = DOWN;
Push(s, top);
flag_stop = true;
} else if (top.y != 0 && !map[top.x][top.y - 1]) {
top.dir = LEFT;
Push(s, top);
flag_stop = true;
}
break;
case RIGHT:
if (top.x != 9 && !map[top.x + 1][top.y]) {
top.dir = DOWN;
Push(s, top);
flag_stop = true;
} else if (top.y != 0 && !map[top.x][top.y - 1]) {
top.dir = LEFT;
Push(s, top);
flag_stop = true;
}
break;
case DOWN:
if (top.y != 0 && !map[top.x][top.y - 1]) {
top.dir = LEFT;
Push(s, top);
flag_stop = true;
}
break;
case LEFT:
map[top.x][top.y] = 0;
break;
}
} else {
next = Top(s);
switch (top.dir) {
case UP:
if (top.y != 11 && !map[top.x][top.y + 1] && next.dir != LEFT) {
top.dir = RIGHT;
Push(s, top);
flag_stop = true;
} else if (top.x != 9 && !map[top.x + 1][top.y] && next.dir != UP) {
top.dir = DOWN;
Push(s, top);
flag_stop = true;
} else if (top.y != 0 && !map[top.x][top.y - 1] && next.dir != RIGHT) {
top.dir = LEFT;
Push(s, top);
flag_stop = true;
}
break;
case RIGHT:
if (top.x != 9 && !map[top.x + 1][top.y] && next.dir != UP) {
top.dir = DOWN;
Push(s, top);
flag_stop = true;
} else if (top.y != 0 && !map[top.x][top.y - 1] && next.dir != RIGHT) {
top.dir = LEFT;
Push(s, top);
flag_stop = true;
}
break;
case DOWN:
if (top.y != 0 && !map[top.x][top.y - 1] && next.dir != RIGHT) {
top.dir = LEFT;
Push(s, top);
flag_stop = true;
}
break;
case LEFT:
map[top.x][top.y] = 0;
break;
}
}
}
}
bool FillStack(Stack s) {
bool has_export = true;
Elem top = Top(s);
do {
Elem nextPosition;
if (top.dir == UP) {
nextPosition.x = top.x - 1;
nextPosition.y = top.y;
} else if (top.dir == RIGHT) {
nextPosition.x = top.x;
nextPosition.y = top.y + 1;
} else if (top.dir == DOWN) {
nextPosition.x = top.x + 1;
nextPosition.y = top.y;
} else {
nextPosition.x = top.x;
nextPosition.y = top.y - 1;
}
if (nextPosition.x == 0 || nextPosition.x == 9 || nextPosition.y == 0 || nextPosition.y == 11) {
if (nextPosition.x == 0)
nextPosition.dir = UP;
else if (nextPosition.y == 11)
nextPosition.dir = RIGHT;
else if (nextPosition.x == 9)
nextPosition.dir = DOWN;
else
nextPosition.dir = LEFT;
Push(s, nextPosition);
map[nextPosition.x][nextPosition.y] = 2;
} else {
if (!map[nextPosition.x - 1][nextPosition.y] && top.dir != DOWN) {
//
nextPosition.dir = UP;
Push(s, nextPosition);
map[nextPosition.x][nextPosition.y] = 2;
} else if (!map[nextPosition.x][nextPosition.y + 1] && top.dir != LEFT) {
//
nextPosition.dir = RIGHT;
Push(s, nextPosition);
map[nextPosition.x][nextPosition.y] = 2;
} else if (!map[nextPosition.x + 1][nextPosition.y] && top.dir != UP) {
//
nextPosition.dir = DOWN;
Push(s, nextPosition);
map[nextPosition.x][nextPosition.y] = 2;
} else if (!map[nextPosition.x][nextPosition.y - 1] && top.dir != RIGHT) {
//
nextPosition.dir = LEFT;
Push(s, nextPosition);
map[nextPosition.x][nextPosition.y] = 2;
} else {
//
RedirectStack(s);
}
}
if (!StackEmpty(s))
top = Top(s);
} while (top.x != 0 && top.x != 9 && top.y != 0 && top.y != 11 && !StackEmpty(s));
//
if (StackEmpty(s))
has_export = false;
return has_export;
//
}
int main() {
//
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 12; j++) {
printf("%d ", map[i][j]);
}
printf("\n");
}
//
Stack s;
InitStack(&s);
//
int init_X, init_Y;
printf("Please enter the position of the init point : x(0<=x<=9),y(0<=y<=11):");
scanf_s("%d %d", &init_X, &init_Y);
while (map[init_X][init_Y] || init_X < 0 || init_X > 9 || init_Y < 0 || init_Y > 11) {
printf("Wrong!The init point should not in the wall or beyond the map!");
printf("Please enter the position of the init point : x(0<=x<=9),y(0<=y<=11):");
scanf_s("%d %d", &init_X, &init_Y);
}
Elem init_point;
init_point.x = init_X;
init_point.y = init_Y;
//
bool flag_init = true;
if (init_X == 0 && init_Y == 0) {
//
if (map[1][0] + map[0][1] == 2)
flag_init = false;
} else if (init_X == 9 && init_Y == 0) {
//
if (map[8][0] + map[9][1] == 2)
flag_init = false;
} else if (init_X == 0 && init_Y == 11) {
//
if (map[0][10] + map[1][11] == 2)
flag_init = false;
} else if (init_X == 9 && init_Y == 11) {
//
if (map[9][10] + map[8][11] == 2)
flag_init = false;
} else if (init_X == 0) {
//
if (map[0][init_Y - 1] + map[1][init_Y] + map[0][init_Y + 1] == 3)
flag_init = false;
} else if (init_Y == 0) {
//
if (map[init_X - 1][0] + map[init_X][1] + map[init_X + 1][0] == 3)
flag_init = false;
} else if (init_X == 9) {
//
if (map[9][init_Y - 1] + map[8][init_Y] + map[9][init_Y + 1] == 3)
flag_init = false;
} else if (init_Y == 11) {
//
if (map[init_X - 1][11] + map[init_X][10] + map[init_X + 1][11] == 3)
flag_init = false;
} else {
//
if (map[init_X][init_Y - 1] + map[init_X - 1][init_Y] + map[init_X][init_Y + 1] + map[init_X + 1][init_Y] == 4)
flag_init = false;
}
if (!flag_init) {
printf("No Export!\n");
exit(0);
}
//
if (init_X - 1 >= 0 && map[init_X - 1][init_Y] == 0) {
//
init_point.dir = UP;
} else if (init_Y + 1 <= 11 && map[init_X][init_Y + 1] == 0) {
//
init_point.dir = RIGHT;
} else if (init_X + 1 <= 9 && map[init_X + 1][init_Y] == 0) {
//
init_point.dir = DOWN;
} else {
//
init_point.dir = LEFT;
}
Push(s, init_point);
Stack minPath;
InitStack(&minPath);
if (FillStack(s)) {
printf("The min size path is:");
if (getStackLength(s) == 2) {
PrintStack(s);
exit(0);
} else {
CopyStack(minPath, s);
int minLength = getStackLength(s);
int tempLength;
while (!StackEmpty(s)) {
RedirectStack(s);
if (StackEmpty(s))
break;
else {
if (FillStack(s)) {
tempLength = getStackLength(s);
if (tempLength < minLength) {
ClearStack(minPath);
CopyStack(minPath, s);
minLength = tempLength;
}
}
}
}
PrintStack(minPath);
}
} else
printf("NO EXPORT");
DeleteStack(s);
DeleteStack(minPath);
return 0;
}