一、DFS介绍
深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法。沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。
深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。
1.1 主要思想
主要思想:不撞南墙不回头。
深度优先遍历的主要思想就是:首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点;当没有未访问过的顶点时,则回到上一个顶点,继续试探访问别的顶点,直到所有的顶点都被访问。沿着某条路径遍历直到末端,然后回溯,再沿着另一条进行同样的遍历,直到所有的顶点都被访问过为止。
1.2 伪代码
void dfs()
{
// 判断是否到达终点
if() {
return;
}
// 尝试每一个可走方向(右下左上)
for(i=0; i<n; i++){
// 判断是否可走,可走调用递归尝试下一步,不可走则尝试该点的其他方向
if () {
// 继续下一步
dfs();
}
}
}
1.3 C++代码
public void DFS( int x, int y )
throws Exception
{
int tx, ty;
int[] pos =
{ x, y };
dfs_posList.add(pos);
// 是否到达目的地
if (mMapView[y][x] == 8)
{
throw new Exception("find");
}
// 顺时针循环,右下左上四个方向
for (int k = 0; k < 4; k++)
{
tx = x + next[k][1];
ty = y + next[k][0];
// 是否出了边界
boolean isOut = tx < 0 || tx >= mapWidth || ty < 0 || ty >= mapHeight;
if (!isOut)
{
// 是否是障碍物
if (mMapView[ty][tx] == 0 && dfs_book[tx][ty] == 0 || mMapView[ty][tx] == 8)
{
dfs_book[tx][ty] = 1;
DFS(tx, ty);
dfs_book[tx][ty] = 0;
}
}
}
}
// 判断方向的数组 int[][] next =
{ { 0, 1 }, // 右 { 1, 0 }, // 下 { 0, -1 }, // 左 { -1, 0 } // 上 };
二、实现方法
1. 首先将根节点放入队列中。
2. 从队列中取出第一个节点,并检验它是否为目标。
如果找到目标,则结束搜寻并回传结果。
否则将它某一个尚未检验过的直接子节点加入队列中。
3. 重复步骤2。
4. 如果不存在未检测过的直接子节点。
将上一级节点加入队列中。
重复步骤2。
5. 重复步骤4。
6. 若队列为空,表示整张图都检查过了——亦即图中没有欲搜寻的目标。结束搜寻并回传“找不到目标”。
C++的实现
定义一个结构体来表达一个二叉树的节点的结构:
1 struct Node {
2 int self; // 数据
3 Node *left; // 左节点
4 Node *right; // 右节点
5 };
那么我们在搜索一个树的时候,从一个节点开始,能首先获取的是它的两个子节点。例如:
A B C D E F G |
A是第一个访问的,然后顺序是B和D、然后是E。然后再是C、F、G。那么我们怎么来保证这个顺序呢?
这里就应该用堆栈的结构,因为堆栈是一个先进后出的顺序。通过使用C++的STL,下面的程序能帮助理解:
const int TREE_SIZE = 9; 3 std::stack<Node *> unvisited; 4 Node nodes[TREE_SIZE]; 5 Node *current; 6 7 //初始化树 8 for (int i = 0; i < TREE_SIZE; i++) { 9 nodes[i].self = i; 10 int child = i * 2 + 1; 11 if (child < TREE_SIZE) // Left child 12 nodes[i].left = &nodes[child]; 13 else 14 nodes[i].left = NULL; 15 child++; 16 if (child < TREE_SIZE) // Right child 17 nodes[i].right = &nodes[child]; 18 else 19 nodes[i].right = NULL; 20 } 21 22 unvisited.push(&nodes[0]); //先把0放入UNVISITED stack 23 24 // 只有UNVISITED不空 25 while (!unvisited.empty()) { 26 current = (unvisited.top()); //当前应该访问的 27 unvisited.pop(); 28 if (current->right != NULL) 29 unvisited.push(current->right); // 把右边压入 因为右边的访问次序是在左边之后 30 if (current->left != NULL) 31 unvisited.push(current->left); 32 cout << current->self << endl; 33 }
参考: http://blog.csdn.net/g11d111/article/details/75645970