當前位置: 首頁>>算法&結構>>正文


深度優先搜索算法之非遞歸實現及實例源碼(原創)

摘要:本文描述了深度優先算法非遞歸實現的思路,並給出了幾個利用深度優先解決的問題的實例代碼

關鍵字: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]深度優先遍曆演示動畫

http://218.65.59.6/xinwen3/news/kj/flash/2004/0426/1301.htm

本文由《純淨天空》出品。文章地址: https://vimsky.com/zh-tw/article/181.html,未經允許,請勿轉載。