DFS(Depth-First-Search)不同于BFS广度优先搜索,它更加侧重于对树/图进行深度搜索,在搜索时,从根节点开始一直往下到没有节点可以搜索为止,在搜索过程中可将路径进行保存。实现DFS深度优先搜索可借用“栈”来实现,递归或者非递归的方法均可,在解决迷宫问题时,在寻找迷宫出口问题上使用DFS是个合适的选择。
如图上所示,灰色部分为墙壁,如果想从“起点”位置到达“终点”,使用DFS时,会将所有“可能”的路径都走一遍,直到无路可走仍未发现终点时,将退回至最近一次分叉路口从另一条路继续往下寻找,直到找到终点位置。
第一次向左走至尽头,没有发现终点,则回到“起点”处,开始往下寻找。
当走到“黑色箭头”标记处时,发现该节点为“分叉点”,故DFS记录这个位置,选择一条路径开始往下寻找。
往下走到尽头后发现找不到尽头,故退回到“分叉点”,开始往右边寻找。
向右走又出现了分叉点,故DFS记录这个位置,选择一条路径开始往上寻找。
走到尽头后发现没有到终点所以回到最近一次“分叉点”进行往下寻找。
找到终点,结束。
DFS最经典的问题之一,寻找迷宫中起点到终点的路径:{{0, 0, 1, 0, 1},
{0, 1, 1, 1, 0},
{0, 0, 0, 0, 0},
{0, 1, 1, 1, 0},
{0, 0, 0, 1, 0}};
2.1.记录二维网格坐标位置、是否为墙壁、是否走过等状态
struct Node
{
int _x;
int _y;
int _value;
bool _IsWall;
bool _IsWalked;
};
vector> Push_Node(std::vector>& push_into)
{
std::vector> push;
int state;
for (int i = 0; i < push_into.size(); i++)
{
std::vector into;
for (int j = 0; j < push_into[i].size(); j++)
{
if (push_into[i][j] == 1)
state = true;
else
state = false;
Node node{ i,j,push_into[i][j],state,false };
into.push_back(node);
}
push.push_back(into);
}
return push;
}
2.2.寻找指定节点的相邻节点,详细代码可参考我之前写过的文章:【C/C++】获取二维数组相邻八个/四个方向的数据
std::vector Find_Beighbors(int x, int y, std::vector>& vec)
{
int max_x = (vec.size() - 1);
int max_y = ((vec[x].size()) - 1);
std::vector list; //扩列存储相邻元素
for (int dx = (x > 0 ? -1 : 0); dx <= (x < max_x ? 1 : 0); ++dx)
{
for (int dy = (y > 0 ? -1 : 0); dy <= (y < max_y ? 1 : 0); ++dy)
{
if ((dx == 0 || dy == 0) && (dx + dy != 0))
{
list.push_back(vec[x + dx][y + dy]);
}
}
}
return list;
}
2.3.核心部分,使用递归进行DFS搜索,递归使用的是系统的栈,简称隐式栈
bool DFS(Node root, Node target, vector>& push_into) //递归调用,隐形栈
{
if (root._x == target._x && root._y == target._y)
return true;
push_into[root._x][root._y]._IsWalked = true;
vector Beighbors = Find_Beighbors(root._x, root._y, push_into);
for (int i = 0; i < Beighbors.size(); i++)
{
if (!push_into[Beighbors[i]._x][Beighbors[i]._y]._IsWall)
{
if (!push_into[Beighbors[i]._x][Beighbors[i]._y]._IsWalked)
{
push_into[Beighbors[i]._x][Beighbors[i]._y]._IsWalked = true;
if (DFS(push_into[Beighbors[i]._x][Beighbors[i]._y], target, push_into))
{
push_into[Beighbors[i]._x][Beighbors[i]._y]._value = 3; //标记路径
printf("(%d,%d)\n",push_into[Beighbors[i]._x][Beighbors[i]._y]._x, push_into[Beighbors[i]._x][Beighbors[i]._y]._y);
return true;
}
}
}
}
return false;
}
起始节点坐标:(0,0),目标节点坐标:(4,4),输出为:
起始节点坐标:(0,0),目标节点坐标:(4,2),输出为: