/* 首先,根據用戶輸入的頂點總數和邊數,構造無向圖,然后以用戶輸入的頂點 為起始點,進行深度優先、廣度優先搜索遍歷,並輸出遍歷的結果。 */ #include <stdlib.h> #include <iostream> #define MVNum 100 //最大的頂點數 using namespace std; /*——————圖的鄰接表存儲表示——————*/ //邊的結點表-在頂點表后面 typedef struct ArcNode { int adjvex; //鄰接點域-該邊所指向頂點的位置下標 struct ArcNode* nextarc; //鏈域-鄰接的下一頂點位置 //otherInfo info; //用來紀錄權值 }ArcNode; //單鏈表表頭-結構體(類似於頭結點) typedef struct VNode { char data; //頂點的信息值 ArcNode* firstarc; //指向第一條依附該頂點的下一結點-指向類型為邊ArcNode }VNode, AdjList[MVNum]; //AdjList鄰接表類型 //圖ALGraph typedef struct { AdjList vertices; //定義一個鄰接表類型,vertices最多有MVNum個 int vexnum; //頂點數 int arcnum; //邊數 }ALGraph; //鏈隊列結構體 typedef struct QNode { int data; struct QNode* next; }QNode,*QueuePtr; //鏈隊頭指針結構體 typedef struct { QueuePtr front; //隊頭 QueuePtr rear; //隊尾 }LinkQueue; //尋找v1,v2的下標 int LocateVex(ALGraph& G, char NodeInfo) { int flag = 0; //匹配NodeInfo for (int i = 0; i < G.vexnum; i++) { if (G.vertices[i].data == NodeInfo) { flag = i; return i; break; } } if (flag) return flag; else exit(errno); } //鄰接表生成無邊圖 void CreateUDG(ALGraph& G) { //輸入數據 cout << "請輸入相應的頂點數與邊數(以空格間隔):" << endl; cin >> G.vexnum >> G.arcnum; //初始化頂點信息 cout << "請輸入" << G.vexnum << "個頂點的信息(以空格間隔):" << endl; for (int i = 0; i < G.vexnum; i++) { cin >> G.vertices[i].data; G.vertices[i].firstarc = NULL; //各頂點結點的指針域置空 } //初始化邊的連接信息 for (int i = 0; i < G.arcnum; i++) { char v1, v2; //v1,v2為一條邊連接的兩個頂點 cout << "請輸入第" << i << "條邊的兩頂點信息(以空格間隔):"; cin >> v1 >> v2; //求v1,v2在vertices的下標 int idx_v1 = LocateVex(G, v1); int idx_v2 = LocateVex(G, v2); //調用邊的結點表,生成以v1為頭結點的單鏈表構成的鄰接表 ArcNode* p1 = new ArcNode; //生成第一個邊連接的結點(后面的那一個) p1->adjvex = idx_v2; //存入結點的下標 //關聯頭結點,用頭插法,插入結點 p1->nextarc = G.vertices[idx_v1].firstarc; G.vertices[idx_v1].firstarc = p1; //調用邊的結點表,生成以v2為頭結點的單鏈表構成的鄰接表 ArcNode* p2 = new ArcNode; //生成第一個邊連接的結點(后面的那一個) p2->adjvex = idx_v1; //存入結點的下標 //關聯頭結點,用頭插法,插入結點 p2->nextarc = G.vertices[idx_v2].firstarc; G.vertices[idx_v2].firstarc = p2; } } //鄰接表的遍歷 void TraverseAdjList(ALGraph& G) { for (int i = 0; i < G.vexnum; i++) { cout << "【" << G.vertices[i].data << "】→"; //臨時頭指針用於遍歷 ArcNode* temp = G.vertices[i].firstarc; //當temp不為空,輸出鏈表 while (temp) { //輸出頂點序號 cout<<"["<<temp->adjvex<<"]"; temp=temp->nextarc; if (temp) cout << "→"; } putchar(10); } } //深度優先遍歷 int visisted_D[MVNum] = { 0 }; //輔助數組 void DFS_AL(ALGraph& G, int v) { //從v頂點開始訪問 cout <<"("<< G.vertices[v].data <<")"; //訪問過后置1 visisted_D[v] = 1; //臨時結點用於遍歷,指向頭結點后一結點 ArcNode *temp = G.vertices[v].firstarc; //循環遍歷 while (temp) { int w = temp->adjvex; //如果輔助數組visisted[w] == 0遞歸調用DFS_AL if (visisted_D[w] == 0) { DFS_AL(G, w); } //temp指向下一結點 temp = temp->nextarc; } } //廣度優先遍歷 int visisted_B[MVNum] = { 0 }; //輔助數組 //隊列初始化 void InitQuenue(LinkQueue& Q) { Q.rear = new QNode; Q.front = Q.rear; Q.front->next = NULL; } //入隊-尾插法 void EnQuenue(LinkQueue& Q,int v) { QNode* cur = new QNode; cur->data = v; cur->next = NULL; Q.rear->next = cur; Q.rear = cur; } //出隊-返回隊頭int u void DeQuenue(LinkQueue& Q, int &u) { QNode* temp = Q.front->next; Q.front->next = temp->next; //隊頭u更新 u = temp->data; //如果最后一個被刪,隊尾指向隊頭 if (Q.rear == temp) { Q.rear = Q.front; } delete temp; } //返回u的第一個鄰結點 int FirstAdjvex(ALGraph& G, int u) { int w = G.vertices[u].firstarc->adjvex; return w; } //返回u的下一個鄰結點 int NextAdjVex(ALGraph& G, int u, int w) { //臨時結點temp指向頭結點的第一個鄰結點,w此時為第一結點序號 ArcNode *temp = G.vertices[u].firstarc; while (temp->adjvex != w) { temp = temp->nextarc; } //若w結點的下一結點不為空,返回結點序號w的下一結點序號 if (temp->nextarc) return temp->nextarc->adjvex; //否則返回-1,使其退出循環 else return -1; delete temp; } void BFS_AL(ALGraph& G, int v) { //從v頂點開始訪問 cout << "(" << G.vertices[v].data << ")"; //訪問過后置1 visisted_B[v] = 1; //創建隊列 LinkQueue Q; InitQuenue(Q); EnQuenue(Q,v); int u = v; //用於找鄰接點 //隊列非空出隊 while (Q.rear != Q.front) { //出隊,並把隊頭置為u DeQuenue(Q, u); for (int w = FirstAdjvex(G, u); w >= 0; w = NextAdjVex(G, u, w)) { //若結點序號w未訪問則進行訪問 if (!visisted_B[w]) { cout << "(" << G.vertices[w].data << ")"; //輸出數據 visisted_B[w] = 1; //打上訪問標記 EnQuenue(Q, w); //將結點w入隊 } }//進行下一次w的鄰結點查找 } } void main() { ALGraph G; //鄰接表生成無邊圖 CreateUDG(G); //遍歷鄰接表 TraverseAdjList(G); //深度優先遍歷 cout << "請問從第幾個頂點開始深度優先遍歷:"; int v; cin >> v; cout << "DFS:"; DFS_AL(G, v-1); putchar(10); //廣度優先遍歷 cout << "請問從第幾個頂點開始廣度優先遍歷:"; cin >> v; cout << "BFS:"; BFS_AL(G, v - 1); putchar(10); system("pause"); }
//深度優先遍歷由遞歸實現。也可用棧來實現(與BFS隊列操作類似)。
//廣度優先遍歷由隊列實現。需要先讓開始進行遍歷的頂點入隊,再進行出隊,但是出隊需保存出隊的結點序號值作為表頭,用於遍歷該層,並同時將輔助數組visisted_B[v]置為1,以表示已經訪問,然后根據鄰接表結構進行類似於樹的層次遍歷操作,每個結點訪問過后都要將visisted_B[v]置為1,當其中一層遍歷完過后,先進的第一個結點出隊,並更新出隊值,同時開始遍歷以該結點序號為頭結點的單鏈表,直到每層遍歷完后結束。
//在廣度優先遍歷過程中,進行出隊操作時,一開始用形參int u來進行接收,導致隊頭值u(表頭)無法更新,造成只能遍歷初始頂點的那一條單鏈表,后改為形參 int &u解決隊頭值更新問題。

