算法思想
DFS:深度优先搜索,采用递归方式进行搜索,为了方便记录搜索过程,使用链栈记录每次访问的节点。搜索到最底层或死胡同则返回上一层,直到找出所有可能的路径。定义搜索顺序为:右、下、左、上。
注意
- 本算法使用自定义结构体,没有使用stack方法。
- 分清楚指针、指向指针的指针、引用变量、实体的区别以及他们的联系。
- 如果为一个指针申请了空间,则一定要初始化空间为NULL,否则会有一大堆混乱。push()方法是将一个新节点插入到原来的链栈里,而不是为原来的栈节点赋值。所以如果不先为申请的空间赋NULL,则该节点空间会乱指。
- 在实际跑的过程中,发现如果只定义栈的指针,并且不申请空间,则不用赋NULL;如果申请开辟空间了,则在使用前一定要先为空间赋NULL。即:LinkStack L;等价于LinkStack L = new StackNode; L = NULL;具体为什么猜测为空间不初始化会乱指,并且如果你不初始化空间,则计算机会默认给他赋一个值,这样申请的几个堆栈空间全部重叠在一起了,会出现异常。
- 因为是链栈,所以很容易出现nullptr空指针问题,因为在不断pop()中很有可能全出栈了,这时候如果想要打印栈则会出现问题。方法是将打印移到pop()前。(这个问题主要是在一开始写的一团乱麻的时候遇到和后来改bug加了很多打印的时候遇到)
- 本方法使用不带头结点的链栈,如果需要,带头结点的也是可以的。
- 入栈出栈一一对应,包括step的加减,不能忘记写。
- 写代码的思路一定要清晰,写着写着可能就糊涂了。因此检查代码的时候力求冷静,不能发癫,检查的步骤应该用代码本身自己跑出来的过程,而不是自己手写的过程。
插个题外话,感觉自己真的很不适合写代码,小小的迷宫问题前前后后写了一周,虽然不是一直都在写,也有干别的事,但是差不多也是花了这么多时间,并且每次出现错误都是自己先崩溃,根本找不到错误在哪,只能寻求他人的帮助。在这里非常感谢耐心帮我看代码改bug的人,并且教会了我找bug的基本方法。(虽然还是不会用打断点的方法找bug,不知道写一个这样简单的程序能不能用打断点的方法呢?欢迎各位大佬点评)
代码实现
这里是我自己重新写的代码,所以没那么多乱七八糟注释,等有时间贴过程。主要是写代码的过程真的是乱七八糟惨不忍睹,我都不忍心再看。。。
代码(纯享版)
#include<iostream>
#include<stdio.h>
#include<malloc.h>
using namespace std;
int map[8][8] =
{
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 1, 0},
{0, 0, 0, 1, 0, 0, 0, 0},
{1, 1, 0, 1, 0, 1, 1, 0},
{0, 0, 0, 1, 0, 0, 1, 1},
{0, 0, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 0, 0},
{0, 0, 0, 0, 0, 1, 0, 0}
};
struct record
{
int r;
int c;
};
typedef struct StackNode
{
record data;
StackNode* next;
}StackNode, * LinkStack;
LinkStack S;
LinkStack S1;
LinkStack S2;
//LinkStack S = new StackNode;
//LinkStack S1 = new StackNode;
//LinkStack S2 = new StackNode;
//int step;
int num = 0;
int MIN = 9999;
//void InitStack(LinkStack& S)
//{
// S->next = NULL;
// //S = NULL;
//}
void push(LinkStack& S, record val)
{
//使用了new申请空间,是否需要初始化?
LinkStack p = new StackNode;
if (p)
{
p->data = val;
p->next = S;
S = p;
}
}
bool StackEmpty(LinkStack& S)
{
if (S == NULL)
return 1;
else
return 0;
}
void pop(LinkStack& S)
{
if (!StackEmpty(S))
{
//使用了new,是否需要初始化?
LinkStack temp = new StackNode;
temp = S;
S = S->next;
delete(temp);
}
}
void print(int step)
{
//S1 = NULL;
//S2 = NULL;
cout << "长度: " << step << endl;
while (!StackEmpty(S))
{
push(S1, S->data);
push(S2, S->data);
pop(S);
}
while (!StackEmpty(S1))
{
push(S, S1->data);
pop(S1);
}
while (!StackEmpty(S2))
{
cout << "(" << S2->data.r << "," << S2->data.c << ") ";
pop(S2);
}
}
void dfs(int row, int col, int x, int y, int step)
{
//cout << "\ndfs(" << row << "," << col << ")" << endl;
//cout << "map[" << row << "][" << col << "]=" << map[row][col] << endl;
//cout << "step测试: " << step << endl;
record d{};
d.r = row;
d.c = col;
if ((row == x) && (col == y))
{
cout << "min: " << MIN << " step: " << step << endl;
if (step < MIN)
MIN = step;
cout << "min: " << MIN << " step: " << step << endl;
cout << "\n最小" << MIN << "步" << endl;
num++;
cout << "\n第" << num << "次" << endl;
//cout << "push(" << row << "," << col << ")" << endl;
push(S, d);
print(step);
//cout << "pop(" << S->data.r << "," << S->data.c << ")" << endl;
pop(S);
//cout << "return" << endl;
return;
}
if ((row < 0) || (col < 0) || (row > 7) || (col > 7))
{
//cout << "return" << endl;
return;
}
if (map[row][col] == 0)
{
map[row][col] = -1;
//cout << "push(" << row << "," << col << ")" << endl;
//cout << "map[" << row << "][" << col << "]=" << map[row][col] << endl;
push(S, d);
//一定是++step和--step而不是step++和step--,否则不会改变step值
dfs(row, col + 1, x, y, ++step);
--step;
dfs(row + 1, col, x, y, ++step);
--step;
dfs(row, col - 1, x, y, ++step);
--step;
dfs(row - 1, col, x, y, ++step);
--step;
map[row][col] = 0;
//cout << "pop(" << S->data.r << "," << S->data.c << ")" << endl;
pop(S);
}
}
int main()
{
//S = NULL;
cout << "请输入终点位置" << endl;
int m, n;
cin >> m >> n;
dfs(0, 0, m, n, 1);
}
运行结果
这个迷宫任何点的走法都实在是太多了,没办法贴出完整代码。最后运行格式也不好看,大概是这样子: