邻接表的构建、DFS、BFS搜索
生活随笔
收集整理的這篇文章主要介紹了
邻接表的构建、DFS、BFS搜索
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
接著上次的文章“圖的構建(鄰接鏈表法)”,鄰接鏈表法構建圖相對來說比較簡單,并且遍歷起來也相對簡單,但是要是動態添加圖的節點和圖的邊,則是實在不方便,不過現在不管那么多,今天的主題是遍歷。?
-?有另外一種圖的構建方法,叫做十字鏈表法,插入刪除比較方便,但是相對來說比較復雜,改天閑著木事的再搞。(其實主要原因是因為三四年前寫的代碼,現在翻出來了,現成的,尼瑪現在讓我從頭寫那么復雜的數據結構,死的心都有了,所以還是等哪天心情好了,無聊了再寫十字鏈表吧)
上篇:圖的構建(鄰接鏈表法)http://blog.csdn.net/sundong_d/article/details/44983671
本次接著上一篇的講,圖的遍歷就是從圖中的某一個頂點除法訪遍圖中的其余頂點,并且使每一個頂點僅被訪問一次。圖的遍歷算法是求解圖的連通性問題、拓撲排序和求解關鍵路徑等算法的基礎深度優先遍歷
假設一個圖,圖中的所有頂點都未曾被訪問,則深度優先遍歷是從圖中的某一個頂點v出發,訪問此頂點,然后找到與v鄰接的并且未被訪問的點m出發訪問,然后從m的未被訪問的鄰接點n出發訪問,再從那個點n的未被訪問的鄰接點出發訪問,出發......訪問......,循環下去,直至圖中所有的和v與路徑想通的頂點都被訪問到;若此時圖中還有頂點沒有被訪問,則另選圖中的一個未曾被訪問的頂點做起始點,重復上述過程,直到圖中的所有頂點都被訪問到為止。此處不太好用語言描述,不知道各位看官看明白沒有,反正我沒糊涂。 下面上個圖(截圖截人家的,自己懶的畫,但是能講明白就好,黑貓、白貓,逮到耗子就是好貓): 遍歷過程: 以圖(a)中的G4為例,深度優先遍歷圖的過程如圖(b)所示。假設從頂點出發進行搜索,在訪問了頂點v1之后,選擇鄰接點v2。因為v2未曾訪問,則從v2出發進行搜索,以此類推,接著從v4,v8,v5出發盡心搜索。在訪問了v5之后,由于v5的鄰接點都被訪問,則回到v8。然后......就這樣一直回到v1,然后又從v1搜索v3,如此進行下去。由此的發哦的訪問序列為: v1-->v2-->v4-->v8-->v5-->v3-->v6-->v7 當然,也可以在首先訪問圖中任何一個點,那樣就會有不通過的訪問序列。 注:圖(c)是廣度優先遍歷的示意圖。 接下來是代碼,C++實現,其實也可以用其他語言寫,道理都是想通的,只不過實現的方式不同 //----------------深度優先遍歷--------------------// //接上篇,上篇中以一個數組存儲所有圖中的頂點,所以如今訪問時,可以用索引來標記該頂點是否被訪問。 bool visited[MAX_VERTEX_NUM]; //訪問標志數組,通過該數組表示頂點是否已訪問,當visited[i]為false時,表示點i并未被訪問。 int FirstAdjVex(ALGraph &G,int v) //找到在圖G中的,與頂點G.vertices[v]相鄰的未曾被訪問的鄰接點 {int i;int n=-1;ArcNode*p;p=G.vertices[v].firstarc;if(p){i=p->adjvex;if(visited[i]==false)n=i;}return n; } int NextAdjVex(ALGraph &G,int v)//功能與上面的函數類似,可以優化,合并為一個函數,但是。。。。我懶! {int i;int n=-1;ArcNode *p;p=G.vertices[v].firstarc;for(i=p->adjvex;i<G.vexnum,p!=NULL;){ i=p->adjvex;if(visited[i]==false){ n=i;break; }elsep=p->nextarc;}return n; } void VisitFuc(ALGraph &G,int v) //訪問輸出 {cout<<G.vertices[v].date<<" "; } void DFS(ALGraph &G,int v)//對圖G做深度優先遍歷,遍歷點從索引為v的頂點開始 {int w;visited[v]=true; //設置索引為v的頂點為已訪問VisitFuc(G,v); //訪問索引為v的頂點//核心:循環遞歸,慢慢揣摩,找到v的未曾訪問的一個鄰接點,訪問;//然后找到v的未曾訪問的另一個鄰接點訪問,直至v的所有鄰接點都被訪問為止for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v))if(!visited[w]) DFS(G,w);//遞歸調用DFS } void DFSTraverse(ALGraph &G) //深度優先遍歷的起始函數,調用此函數開始遍歷。 {int v;for(v=0;v<G.vexnum;v++) visited[v]=false;//初始化,所有點都為被訪問,統統設為falsecout<<"深度優先搜索:"<<endl;for(v=0;v<G.vexnum;v++) //確保遍歷所有的點{if(!visited[v])//如果未被訪問DFS(G,v);//對該頂點v調用DFS方法} }廣度優先遍歷
廣度優先遍歷是按照圖的層次結構遍歷的過程。 簡單理解就是訪問圖中的一個點之后,一次訪問v的各個未曾訪問過的鄰接點,然后分別從這些鄰接點出發,依次訪問它們的鄰接點,并且使“先被訪問的頂點的鄰接點”先于“后被訪問的頂點的鄰接點”被訪問。就像向湖面投一粒石子,激起一層的波紋。我們訪問一個點,先把這個點的所有未被訪問的鄰接點依次全部訪問,然后再在已經訪問的的鄰接點中找到那個最早被訪問的點,從這個點出發,訪問這個點所有未被訪問的鄰接點,如此循環下去。 如圖(c)(此圖在上面深度優先遍歷的那個圖里面),是對圖G4進行廣度優先遍歷。沙鷗縣訪問v1和v1的鄰接點v2和v3,然后依次訪問v2的鄰接點v4和v5及v3的鄰接點v6和v7,最后訪問v4的鄰接點v8。由于這些頂點的鄰接點均已經被訪問,并且圖中所有頂點都被訪問,由此完成了圖的遍歷。 頂點訪問序列:v1-->v2-->v3-->v4-->v5-->v6-->v7-->v8 和深度優先遍歷類似,我們在遍歷過程中需要一個訪問標志數組。并且,為了順序訪問路徑長度為2、3、...的頂點,需要附設隊列以存儲已經被訪問的路徑長度為1,2...的頂點。 上代碼: //----------------廣度優先遍歷--------------------//void BFSTraverse(ALGraph &G) {int v;int w;queue<int> q; //STL隊列for(v=0;v<G.vexnum;v++)visited[v]=false; //初始化,標記數組設置為falsecout<<"廣度優先搜索:";for(v=0;v<G.vexnum;v++){if(!visited[v])//如果未曾被訪問{visited[v]=true;//標記為已訪問VisitFuc(G,v); //訪問該點q.push(v); //v進隊//此處用隊列的含義:每次訪問一個點,把該點入隊,當對這個點進行了廣度優先遍歷,也就是所有鄰接點都被訪問了,該點就出隊//所以,當對列不為空時,說明還有頂點沒有被進行廣度優先遍歷。需要繼續while(q.empty()!=true)//當q不為空{v = q.front();q.pop();//出隊//w為v的尚未訪問的鄰接點for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v))//依次訪問v的所有為被訪問的鄰接點{ if(!visited[w]){visited[w]=true;VisitFuc(G,w);q.push(w);}}}}} }好了,圖的兩種遍歷方法講完了,下面貼上整個工程的代碼,代碼中是沒有這么多注釋的,當有看不懂的時候,參考上一篇博客和本篇博客中對程序的注釋
#include<iostream> #include<string> #include<queue> using namespace std; #define ERROR 1 #define MAX_VERTEX_NUM 100 typedef struct ArcNode{int adjvex;struct ArcNode *nextarc;string info; }ArcNode; typedef struct VNode{char date;ArcNode * firstarc; }VNode,AdjList[MAX_VERTEX_NUM]; typedef struct{AdjList vertices;int vexnum,arcnum; //當前圖的vexnum頂點數和arcnum弧數int kind; }ALGraph; int LocateVex(ALGraph &G,char &v1) {int i;for(i=0;i<G.vexnum;i++){if(G.vertices[i].date==v1)return i;}if(i>=G.vexnum)return ERROR;else return 0; } void CreateDG(ALGraph &G) {ArcNode *p,*q;char v1,v2;char v;int i,j,k,n;cout<<"請輸入圖的頂點數和弧數:"<<endl;cin>>G.vexnum;cin>>G.arcnum;cout<<"請輸入頂點:"<<endl;for(i=0;i<G.vexnum;i++){cin>>v;G.vertices[i].date=v;G.vertices[i].firstarc=NULL;}cout<<"請輸入弧尾和弧頭:";for(k=0;k<G.arcnum;k++){cin>>v1;cin>>v2;i=LocateVex(G,v1);j=LocateVex(G,v2);if(G.vertices[i].firstarc==NULL){p=(ArcNode *)new ArcNode;G.vertices[i].firstarc=p;q=G.vertices[i].firstarc;}else{q=G.vertices[i].firstarc;for(n=0;n<G.arcnum;n++,q=q->nextarc){if(!q->nextarc)break;}p=(ArcNode *)new ArcNode;q->nextarc=p;q=q->nextarc;}q->adjvex=j;q->nextarc=NULL; }cout<<"圖構建成功!"; } //----------------深度優先遍歷--------------------//bool visited[MAX_VERTEX_NUM]; int FirstAdjVex(ALGraph &G,int v) {int i;int n=-1;ArcNode*p;p=G.vertices[v].firstarc;if(p){i=p->adjvex;if(visited[i]==false)n=i;}return n; } int NextAdjVex(ALGraph &G,int v) {int i;int n=-1;ArcNode *p;p=G.vertices[v].firstarc;for(i=p->adjvex;i<G.vexnum,p!=NULL;){ i=p->adjvex;if(visited[i]==false){ n=i;break; }elsep=p->nextarc;}return n; }void VisitFuc(ALGraph &G,int v) {cout<<G.vertices[v].date<<" "; } void DFS(ALGraph &G,int v) {int w;visited[v]=true;VisitFuc(G,v); for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v))if(!visited[w]) DFS(G,w);} void DFSTraverse(ALGraph &G) {int v;for(v=0;v<G.vexnum;v++)visited[v]=false;cout<<"深度優先搜索:"<<endl;for(v=0;v<G.vexnum;v++){if(!visited[v])DFS(G,v);} } //----------------廣度優先遍歷--------------------//void BFSTraverse(ALGraph &G) {int v;int w;queue<int> q; //STL隊列for(v=0;v<G.vexnum;v++)visited[v]=false; // InitQueue(Q);cout<<"廣度優先搜索:";for(v=0;v<G.vexnum;v++){if(!visited[v]){visited[v]=true;VisitFuc(G,v);q.push(v); //v進隊while(q.empty()!=true){v = q.front();q.pop();for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v)){ if(!visited[w]){visited[w]=true;VisitFuc(G,w);q.push(w);}}}}} } / void menu() {cout<<'\n';cout<<" //---------------圖的基本操作---------------//"<<endl;cout<<" ** 1、圖的構建 **"<<endl;cout<<" ** 2、深度優先遍歷 **"<<endl;cout<<" ** 3、廣度優先遍歷 **"<<endl;cout<<" --------------------------------------------"<<endl;cout<<"請輸入數字進行選擇:"<<endl; } int main() {ALGraph G;int i;menu();cin>>i;while(i<4){switch(i){case 1:CreateDG(G);break;case 2:DFSTraverse(G);cout<<endl;break;case 3:BFSTraverse(G);cout<<endl;break;default:return ERROR;}menu();cin>>i;}return 0; }總結
以上是生活随笔為你收集整理的邻接表的构建、DFS、BFS搜索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: USB Flash Drives
- 下一篇: node.js模块引擎