參考:
http://www.cnblogs.com/kubixuesheng/p/4399705.html
http://www.cnblogs.com/dolphin0520/archive/2011/07/13/2105236.html
圖的深度優先遍歷遞歸算法大概如下:

1 //訪問標志數組 2 int visited[MAX] = {0}; 3 4 //用鄰接表方式實現深度優先搜索(遞歸方式) 5 //v 傳入的是第一個需要訪問的頂點 6 void DFS(MGraph G, int v) 7 { 8 //圖的頂點的搜索指針 9 ArcNode *p; 10 //置已訪問標記 11 visited[v] = 1; 12 //輸出被訪問頂點的編號 13 printf("%d ", v); 14 //p指向頂點v的第一條弧的弧頭結點 15 p = G.vertices[v].firstarc; 16 while (p != NULL) 17 { 18 //若p->adjvex頂點未訪問,遞歸訪問它 19 if (visited[p->adjvex] == 0) 20 { 21 DFS(G, p->adjvex); 22 } 23 //p指向頂點v的下一條弧的弧頭結點 24 p = p->nextarc; 25 } 26 }
圖的廣度優先遍歷算法大概如下:

1 #include <iostream> 2 #include<queue> 3 using namespace std; 4 5 const int MAX = 10; 6 //輔助隊列的初始化,置空的輔助隊列Q,類似二叉樹的層序遍歷過程 7 queue<int> q; 8 //訪問標記數組 9 bool visited[MAX]; 10 //圖的廣度優先搜索算法 11 void BFSTraverse(Graph G, void (*visit)(int v)) 12 { 13 int v = 0; 14 //初始化訪問標記的數組 15 for (v = 0; v < G.vexnum; v++) 16 { 17 visited[v] = false; 18 } 19 //依次遍歷整個圖的結點 20 for (v = 0; v < G.vexnum; v++) 21 { 22 //如果v尚未訪問,則訪問 v 23 if (!visited[v]) 24 { 25 //把 v 頂點對應的數組下標處的元素置為真,代表已經訪問了 26 visited[v] = true; 27 //然后v入隊列,利用了隊列的先進先出的性質 28 q.push(v); 29 //訪問 v,打印處理 30 cout << q.back() << " "; 31 //隊不為空時 32 while (!q.empty()) 33 { 34 //隊頭元素出隊,並把這個出隊的元素置為 u,類似層序遍歷 35 Graph *u = q.front(); 36 q.pop(); 37 //w為u的鄰接頂點 38 for (int w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G,u,w)) 39 { 40 //w為u的尚未訪問的鄰接頂點 41 if (!visited[w]) 42 { 43 visited[w] = true; 44 //然后 w 入隊列,利用了隊列的先進先出的性質 45 q.push(w); 46 //訪問 w,打印處理 47 cout << q.back() << " "; 48 }//end of if 49 }//end of for 50 }//end of while 51 }//end of if 52 }// end of for 53 }
上面是用鄰接表結構實現的代碼。下面是用鄰接矩陣實現的代碼,包含遞歸深搜、非遞歸深搜、廣搜,可以參考一下:

1 #include<iostream> 2 #include<queue> 3 #include<stack> 4 #include<stdlib.h> 5 #define MAX 100 6 using namespace std; 7 8 typedef struct 9 { 10 int edges[MAX][MAX]; //鄰接矩陣 11 int n; //頂點數 12 int e; //邊數 13 }MGraph; 14 15 bool visited[MAX]; //標記頂點是否被訪問過 16 17 void creatMGraph(MGraph &G) //用引用作參數 18 { 19 int i,j; 20 int s,t; //存儲頂點編號 21 int v; //存儲邊的權值 22 for(i=0;i<G.n;i++) //初始化 23 { 24 for(j=0;j<G.n;j++) 25 { 26 G.edges[i][j]=0; 27 } 28 visited[i]=false; 29 } 30 for(i=0;i<G.e;i++) //對矩陣相鄰的邊賦權值 31 { 32 scanf("%d %d %d",&s,&t,&v); 33 //兩個頂點確定一條邊 34 //輸入邊的頂點編號以及權值 35 G.edges[s][t]=v; 36 } 37 } 38 39 void DFS(MGraph G,int v) //深度優先搜索 40 { 41 int i; 42 printf("%d ",v); //訪問結點v 43 visited[v]=true; 44 for(i=0;i<G.n;i++) //訪問與v相鄰的未被訪問過的結點 45 { 46 if(G.edges[v][i]!=0&&visited[i]==false) 47 { 48 DFS(G,i);//若沒訪問則繼續,而且根據頂點的序號按數序訪問 49 } 50 } 51 } 52 //stack彈出順序有問題 53 void DFS1(MGraph G,int v) //非遞歸實現 54 { 55 stack<int> s; 56 printf("%d ",v); //訪問初始結點 57 visited[v]=true; 58 s.push(v); //入棧 59 while(!s.empty()) 60 { 61 int i,j; 62 i=s.top(); //取棧頂頂點 63 for(j=0;j<G.n;j++) //訪問與頂點i相鄰的頂點 64 { 65 if(G.edges[i][j]!=0&&visited[j]==false) 66 { 67 printf("%d ",j); //訪問 68 visited[j]=true; 69 s.push(j); //訪問完后入棧 70 break; //找到一個相鄰未訪問的頂點,訪問之后則跳出循環 71 } 72 } 73 //對於節點4,找完所有節點發現都已訪問過或者沒有臨邊,所以j此時=節點總數,然后把這個4給彈出來 74 直到彈出1,之前的深度搜索的值都已彈出,有半部分還沒有遍歷,開始遍歷有半部分 75 if(j==G.n) //如果與i相鄰的頂點都被訪問過,則將頂點i出棧 76 s.pop(); 77 } 78 } 79 80 void BFS(MGraph G,int v) //廣度優先搜索 81 { 82 queue<int> Q; //STL模板中的queue 83 printf("%d ",v); 84 visited[v]=true; 85 Q.push(v); 86 while(!Q.empty()) 87 { 88 int i,j; 89 i=Q.front(); //取隊首頂點 90 Q.pop();//彈出一個,然后遍歷這個節點的子節點,然后遍歷完再彈出下一個 91 for(j=0;j<G.n;j++) //廣度遍歷 92 { 93 if(G.edges[i][j]!=0&&visited[j]==false) 94 { 95 printf("%d ",j); 96 visited[j]=true; 97 Q.push(j); 98 } 99 } 100 } 101 } 102 103 int main(void) 104 { 105 int n,e; //建立的圖的頂點數和邊數 106 while(scanf("%d %d",&n,&e)==2&&n>0) 107 { 108 MGraph G; 109 G.n=n; 110 G.e=e; 111 creatMGraph(G); 112 DFS(G,0); 113 printf("\n"); 114 // DFS1(G,0); 115 // printf("\n"); 116 // BFS(G,0); 117 // printf("\n"); 118 } 119 return 0; 120 }
在網絡上查了很多資料,又去看了好幾本教材,發現這些地方對圖的深度優先遍歷算法的講解,基本都是用遞歸算法實現的。對非遞歸算法實現描述不是很多。上面第三段代碼實現了非遞歸深搜算法。
在尋找資料過程中,也在思考如何實現,大概設計了如下兩種算法:
算法一:(這個是一個錯誤的思路)
1 st.push(v1)//出發點入棧 2 while(!st.empty()) 3 { 4 temp=st.top(); st.pop();//臨時備份棧頂節點到temp,刪除棧頂節點 5 printf(temp);//訪問temp(原先的棧頂節點) 6 根據temp尋找所有未曾訪問的相鄰節點,並把這些節點入棧 7 }
算法二:
1 printf(v1);//訪問出發節點 2 st.push(v1);//出發點入棧 3 while(!st.empty()) 4 { 5 temp=st.top();//讀取棧頂節點到temp 6 循環遍歷temp的所有相鄰節點: 7 { 8 如果(發現一個未曾訪問的相鄰節點w): 9 { 10 printf(w);//訪問節點w 11 st.push(w);//把w入棧 12 退出循環 13 } 14 } 15 if(temp沒有未曾訪問的相鄰節點) 16 st.pop();//刪除棧頂節點 17 }
這兩種算法,假如僅僅是對樹進行深搜,應該是沒有錯的。但是對圖進行深搜,算法一確實不正確的。看下面這個例子:
對這個圖從V0出發做深搜,假如按照算法一操作,假設節點入棧順序為:V0,V1,V3,……
其中v1和V3入棧時,V0已經出棧。但是取出棧頂V3做訪問操作,然后再把V3的相鄰未曾訪問節點入棧,則會使得V1再一次 入棧。所以算法一不正確。