圖的深度優先遍歷(DFS)和廣度優先遍歷(BFS)


  從圖中某一頂點出發訪遍圖中其余頂點,且使每一個頂點僅被訪問一次,這一過程就叫做圖的遍歷(Traversing Graph)

****注:圖的建立上一篇博客《圖的鄰接矩陣存儲實現》已經放了源代碼了,這里要運行只要按代碼加上相應的文件就能執行****

深度優先遍歷(DFS,Depth_First_Search):
  從圖中某個頂點V出發,訪問此頂點,然后從V的未被訪問的鄰接點觸犯深度優先遍歷圖,直至圖中所有和V有路徑相通的頂點都被訪問到。相當於樹的前序遍歷。針對非連通圖,只要對每個連通分量分別進行深度優先遍歷,即在先前一個頂點進行一次深度優先遍歷后,若圖中尚有頂點未被訪問,則另選圖中一個未曾被訪問的頂點作起始點,重復上述過程,直至圖中所有頂點都被訪問到為止。


右圖是遞歸遍歷的過程,其實每一層都是從A結點開始搜尋滿足條件的點
/* DFS.h */
#ifndef __DFS_H__
#define __DFS_H__
#include"Graph.h"
namespace meihao
{
        void DFS(const meihao::Graph& g,int vi,bool*& visited);  //參數->圖和頂點數組中某個頂點的下標
        void DFSTraversal(const meihao::Graph& g);
};
#endif

/* testMain.cpp */
#include"DFS.h"
#include<iostream>
int main()
{
        meihao::Graph g("data.txt");
        meihao::DFSTraversal(g);
        cout<<endl;
        system("pause");
}

/* data.txt */
9
A B C D E F G H I
0 1 0 0 0 1 0 0 0
1 0 1 0 0 0 1 0 1
0 1 0 1 0 0 0 0 1
0 0 1 0 1 0 1 1 1
0 0 0 1 0 1 0 1 0
1 0 0 0 1 0 1 0 0
0 1 0 1 0 1 0 1 0
0 0 0 1 1 0 1 0 0
0 1 1 1 0 0 0 0 0 
/* DFS.cpp */
#include"DFS.h"
namespace meihao
{
//算法都是基於鄰接矩陣實現的
        void DFS(const meihao::Graph& g,int vi,bool*& visited)
        {
                visited[vi] = true;  //修改第vi個結點的訪問標記為true
                cout<<g.getGraphVertexData(vi)<<" ";
                for(int idx=0;idx!=g.getGraphVertexNumber();++idx)
                {
                        if(1==g.getGraphEdgeWeight(vi,idx)&&
                                false==visited[idx])  //如果(vi,idx)之間存在邊(==1),並且第idx個頂點還沒有訪問過
                        {
                                DFS(g,idx,visited);  //遞歸遍歷第idx個頂點
                        }
                }
        }
        void DFSTraversal(const meihao::Graph& g)
        {
                bool* visited = new bool[g.getGraphVertexNumber()]();
                for(int idx=0;idx!=g.getGraphVertexNumber();++idx)
                {
                        visited[idx] = false;  //初始化訪問標記,全部為false,表示未訪問
                }
                for(int idx=0;idx!=g.getGraphVertexNumber();++idx)
                {
                        if(false==visited[idx])  //隨便選一個點,如果未訪問過,就從它開始深度優先遍歷
                                DFS(g,idx,visited);
                }
        }
};



廣度優先遍歷(Breadth First Search):
 類似於圖的層序遍歷,
  
/* BFS.h */
#ifndef __BFS_H__
#define __BFS_H__
#include"Graph.h"
namespace meihao
{
        void BFSTraversal(const meihao::Graph& g);
};
#endif

/* test.cpp */
#include"BFS.h"
#include<iostream>
int main()
{
        meihao::Graph g("data.txt");
        meihao::BFSTraversal(g);
        cout<<endl;
        system("pause");
}

/* data.txt */
9
A B C D E F G H I
0 1 0 0 0 1 0 0 0
1 0 1 0 0 0 1 0 1
0 1 0 1 0 0 0 0 1
0 0 1 0 1 0 1 1 1
0 0 0 1 0 1 0 1 0
1 0 0 0 1 0 1 0 0
0 1 0 1 0 1 0 1 0
0 0 0 1 1 0 1 0 0
0 1 1 1 0 0 0 0 0 

/* BFS.cpp */
#include"BFS.h"
#include<queue>
namespace meihao
{
        void BFSTraversal(const meihao::Graph& g)
        { //廣度優先遍歷相當於層序遍歷
                queue<int> rootNode;  //存放圖的頂點
                bool* visited = new bool[g.getGraphVertexNumber()];
                for(int idx=0;idx!=g.getGraphVertexNumber();++idx)
                {
                        visited[idx] = false;
                }
                for(int idx=0;idx!=g.getGraphVertexNumber();++idx)
                { //if語句可以確保如果圖中有多個連通分量,也能每個點都訪問到
                        if(false==visited[idx])  //如果該結點沒有訪問到
                        {
                                //訪問
                                cout<<g.getGraphVertexData(idx)<<" ";
                                visited[idx] = true;
                                rootNode.push(idx);
                                while(!rootNode.empty())  //把剛剛訪問到的結點的下一層結點訪問並入隊列
                                {
                                        for(int iidx=0;iidx!=g.getGraphVertexNumber();++iidx)
                                        {
                                                if(1==g.getGraphEdgeWeight(rootNode.front(),iidx)&&
                                                        false==visited[iidx])
                                                {
                                                        cout<<g.getGraphVertexData(iidx)<<" ";
                                                        visited[iidx] = true;
                                                        rootNode.push(iidx);
                                                }
                                        }
                                        rootNode.pop();  //最先訪問的一個結點出隊列
                                }
                        }
                }
        }
};

兩種遍歷算法在時間復雜度上是一樣的
深度優先遍歷算法適合圖和邊都非常多,要找到合適的頂點
廣度優先遍歷算法適合不斷擴大遍歷范圍時找到相對最優


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM