摘要:本文描述了深度優先算法非遞歸實現的思路,並給出了幾個利用深度優先解決的問題的實例代碼
關鍵字:DFS,非遞歸,深度優先,圖論,搜索,經典實例,源碼
深度優先搜索算法需要了解深度優先遍曆的執行過程,本文中利用一個棧來模擬遞歸實現中係統設置的工作棧,算法的偽代碼描述為:
(1)初始化棧
(2)輸出起始節點,並標記為已訪問,將該節點壓入棧
(3)While(棧不為空)
a.取得棧頂節點Top,注意不要從站內刪除;
b.遍曆棧頂節點Top的相鄰節點adjacentNode,如果該節點adjacentNode未被標記為已
訪問,則
輸出節點adjacentNode;
標記adjacentNode為已訪問;
把adjacentNode壓入棧;
c.如果沒有滿足條件的相鄰節點adjacentNode,將棧頂節點Top出棧;
使用情形:
1.深度優先策略常用於連通圖的遍曆
2.深度優先策略也廣泛應用於尋找一條滿足某種條件的路徑。
算法的時間複雜度為O(n),其中n為節點個數。
經典實例源碼:
1.圖的節點遍曆(C++,VC6.0/VS2005)=================================================
//////////////////////////////////
//深度優先之節點遍曆
//1---5
//| |
//2---4--6----8
//| |
//3------7
// 1 2 3 4 5 6 7 8
//1 0 1 0 0 1 0 0 0
//2 1 0 1 1 0 0 0 0
//3 0 1 0 0 0 0 1 0
//4 0 1 0 0 1 1 0 0
//5 1 0 0 1 0 0 0 0
//6 0 0 0 1 0 0 1 1
//7 0 0 1 0 0 1 0 0
//8 0 0 0 0 0 1 0 0
#include
#include
using namespace std;
//節點數
#define M 8
//圖的矩陣表示
int matrix[M][M] =
{
0, 1, 0, 0, 1, 0, 0, 0,
1, 0, 1, 1, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 1, 1, 0, 0,
1, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 1, 1,
0, 0, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0
};
//訪問標記,初始化為0,
int visited[M + 1];
//graph traverse
void GT_DFS()
{
visited[1] = 1;
stack s;
cout << 1 << " ";
s.push(1);
while(!s.empty())
{
int top = s.top();
int i ;
for(i = 1; i <= M; ++i)
{
if(visited[i] == 0 && matrix[top - 1][i - 1 ] == 1)
{
visited[i] = 1;
s.push(i);
cout << i << " ";
break;
}
}
if( i == M + 1)
{
s.pop();
}
}
}
int main()
{
GT_DFS();
system("pause");
return 0;
}
2.迷宮問題(C++,VC6.0/VS2005)=====================================================
////////////////////////////////////////////////
//深度優先搜索之迷宮問題
#include
#include
using namespace std;
#define M 10
#define N 10
//迷宮矩陣,1為通道,0為障礙
//入口(1,0),出口(9,9)
int Matrix[M][N]={
0,1,1,1,0,0,0,0,0,0,
1,1,0,1,0,1,1,1,1,0,
0,1,0,1,1,1,0,0,0,0,
0,0,0,0,0,1,0,0,0,0,
0,1,1,1,1,1,0,0,0,0,
0,1,0,0,0,0,0,0,0,0,
0,1,1,1,0,0,1,1,1,0,
0,0,1,1,1,1,1,0,1,0,
0,0,1,1,0,0,0,0,1,0,
0,0,1,0,0,0,0,0,1,1};
//標記數組,初始化為0
bool visited[M * N + 1] ;
//節點
struct Node
{
int x;
int y;
Node(int i,int j)
{
x = i;
y = j;
}
};
//////////////////////////////////
/*
0
----------------->y
|
|
|
|
|
V
x
*/
//右下上左
int x_off[] = {0,1,-1,0};
int y_off[] = {1,0,0,-1};
//輸出迷宮
void PrintMatrix()
{
cout << "入口(1,0),出口(9,9)的迷宮,1為通道,0為障礙:" << endl;
for(int i = 0; i < M; ++i)
{
for(int j = 0; j < N; ++j)
cout << Matrix[i][j];
cout << endl;
}
}
//輸出一條路徑
//由於入棧路徑是正序,要倒過來輸出才是從入口到出口的路勁
void PrintPath(stack s)
{
cout << "一條迷宮路徑:" << endl;
stack t;
while(!s.empty())
{
t.push(s.top());
s.pop();
}
while(!t.empty())
{
cout << "(" << t.top().x << "," << t.top().y << ")->";
t.pop();
}
cout << endl;
}
//深度優先搜索一條可能的路徑
void MAZE_DFS()
{
//1.初始化棧
stack s;
Node start(1,0);
s.push(start);
visited[0] = 1;
while(!s.empty())
{
//2.取得棧頂元素(注意不從棧內刪除)
Node top = s.top();
//3.遍曆棧頂元素的鄰節點
//右節點
//下節點
//上節點
//左節點
int i;
for(i = 0; i < 4; ++i)
{
int nx = top.x + x_off[i];
int ny = top.y + y_off[i];
if(nx >= 0 && nx < N && ny>=0 && ny< M && visited[nx * N + ny] != 1 && Matrix[nx][ny] == 1)
{
//4.把滿足條件的元素標記為已處理,並壓入棧內
Node newNode(nx,ny);
visited[nx*N + ny] = 1;
s.push(newNode);
//找到出口,終止搜索
if(nx == 9 && ny == 9)
{
//輸出找到的路徑
PrintPath(s);
return;
}
break;
}
}
//5.當前節點沒有滿足條件的鄰節點,把當前棧頂元素刪除
if(i == 4)
{
s.pop();
}
}
}
//測試代碼主函數
void main()
{
PrintMatrix();
MAZE_DFS();
system("pause");
}
參考文獻:
[1] 深度優先遍曆算法的非遞歸實現jsj.ccut.edu.cn/sjjg/index.php
[2]深度優先遍曆演示動畫