寫在前面
圖的存儲結構有兩種:一種是基於二維數組的鄰接矩陣表示法。
另一種是基於鏈表的的鄰接表表示法。
在鄰接矩陣中,可以如下表示頂點和邊連接關系:
說明:
將頂點對應為下標,根據橫縱坐標將矩陣中的某一位置值設為1,表示兩個頂點向聯接。
圖示表示的是無向圖的鄰接矩陣,從中我們可以發現它們的分布關於斜對角線對稱。
我們在下面將要討論的是下圖的兩種遍歷方法(基於矩陣的):
我們已經說明了我們要用到的是鄰接矩陣表示法,那么我首先要來構造圖:
1.深度優先遍歷算法
分析深度優先遍歷
從圖的某個頂點出發,訪問圖中的所有頂點,且使每個頂點僅被訪問一次。這一過程叫做圖的遍歷。
深度優先搜索的思想:
①訪問頂點v;
②依次從v的未被訪問的鄰接點出發,對圖進行深度優先遍歷;直至圖中和v有路徑相通的頂點都被訪問;
③若此時圖中尚有頂點未被訪問,則從一個未被訪問的頂點出發,重新進行深度優先遍歷,直到圖中所有頂點均被訪問過為止。
比如:
在這里為了區分已經訪問過的節點和沒有訪問過的節點,我們引入一個一維數組bool visited[MaxVnum]用來表示與下標對應的頂點是否被訪問過,
流程:
☐ 首先輸出 V1,標記V1的flag=true;
☐ 獲得V1的鄰接邊 [V2 V3],取出V2,標記V2的flag=true;
☐ 獲得V2的鄰接邊[V1 V4 V5],過濾掉已經flag的,取出V4,標記V4的flag=true;
☐ 獲得V4的鄰接邊[V2 V8],過濾掉已經flag的,取出V8,標記V8的flag=true;
☐ 獲得V8的鄰接邊[V4 V5],過濾掉已經flag的,取出V5,標記V5的flag=true;
☐ 此時發現V5的所有鄰接邊都已經被flag了,所以需要回溯。(左邊黑色虛線,回溯到V1,回溯就是下層遞歸結束往回返)
☐
☐ 回溯到V1,在前面取出的是V2,現在取出V3,標記V3的flag=true;
☐ 獲得V3的鄰接邊[V1 V6 V7],過濾掉已經flag的,取出V6,標記V6的flag=true;
☐ 獲得V6的鄰接邊[V3 V7],過濾掉已經flag的,取出V7,標記V7的flag=true;
☐ 此時發現V7的所有鄰接邊都已經被flag了,所以需要回溯。(右邊黑色虛線,回溯到V1,回溯就是下層遞歸結束往回返)
深度優先搜索的代碼
2.廣度優先搜索算法
分析廣度優先遍歷
所謂廣度,就是一層一層的,向下遍歷,層層堵截,還是這幅圖,我們如果要是廣度優先遍歷的話,我們的結果是V1 V2 V3 V4 V5 V6 V7 V8。
廣度優先搜索的思想:
① 訪問頂點vi ;
② 訪問vi 的所有未被訪問的鄰接點w1 ,w2 , …wk ;
③ 依次從這些鄰接點(在步驟②中訪問的頂點)出發,訪問它們的所有未被訪問的鄰接點; 依此類推,直到圖中所有訪問過的頂點的鄰接點都被訪問;
說明:
為實現③,需要保存在步驟②中訪問的頂點,而且訪問這些頂點的鄰接點的順序為:先保存的頂點,其鄰接點先被訪問。 這里我們就想到了用標准模板庫中的queue隊列來實現這種先進現出的服務。
老規矩我們還是走一邊流程:
說明:
☐將V1加入隊列,取出V1,並標記為true(即已經訪問),將其鄰接點加進入隊列,則 <—[V2 V3]
☐取出V2,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[V3 V4 V5]
☐取出V3,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[V4 V5 V6 V7]
☐取出V4,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[V5 V6 V7 V8]
☐取出V5,並標記為true(即已經訪問),因為其鄰接點已經加入隊列,則 <—[V6 V7 V8]
☐取出V6,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[V7 V8]
☐取出V7,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[V8]
☐取出V8,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[]
兩種表示法:
鄰接矩陣完整代碼:

#include<stdio.h> #include<stdlib.h> #include<malloc.h> //鄰接矩陣 #define OK 1 #define ERROR 0 #define MAXNUM 10 typedef int Status; typedef char ElemType; typedef struct { int vnum; //頂點數 int anum; //弧/邊數 ElemType vex[MAXNUM]; //存儲頂點 int arc[MAXNUM][MAXNUM]; //存儲邊關系 }MGraph; int Location(MGraph G, ElemType e) { int v; for (v = 0; v<G.vnum; v++) if (G.vex[v] == e)return v; return -1; } Status CreateGraph(MGraph &G, int vnum, int anum, ElemType v[], ElemType a[]) //數組生成圖 { int k; G.vnum = vnum; //獲取數組頂點數 G.anum = anum; //獲取數組邊數 for (k = 0; k<G.vnum; k++) G.vex[k] = v[k]; for (int i = 0; i<G.vnum; i++) { for (int j = 0; j<G.vnum; j++) G.arc[i][j] = 0; } int t = 0; int p, q; for (k = 0; k<G.anum; k++) { ElemType m, n; m = a[t++]; n = a[t++]; t++; p = Location(G, m); q = Location(G, n); G.arc[p][q] = 1; G.arc[q][p] = 1; } return OK; } void Print(MGraph G) { int v; printf("頂點序列為:\n"); for (v = 0; v<G.vnum; v++) printf("%3c", G.vex[v]); printf("\n"); printf("邊的二維數組關系:\n"); for (int i = 0; i<G.vnum; i++) { for (int j = 0; j<G.vnum; j++) printf("%3d", G.arc[i][j]); printf("\n"); } printf("\n"); } int FirstAdjVex(MGraph G, int i) { int v; if (i<0 || i >= G.vnum)return -1; for (v = 0; v<G.vnum; v++) if (G.arc[i][v] == 1)return v; return -1; } int NextAdjVex(MGraph G, int i, int j) { if (i<0 || i >= G.vnum)return -1; if (j<0 || j >= G.vnum)return -1; for (int v = j + 1; v<G.vnum; v++) if (G.arc[i][v] == 1)return v; return -1; } //DFS遍歷 int visited[MAXNUM]; void DFS(MGraph G, int v); void DFSTraverse(MGraph G) { printf("深度優先遍歷為:\n"); int v; for (v = 0; v<G.vnum; v++) visited[v] = 0; for (v = 0; v<G.vnum; v++) { if (visited[v] == 0)DFS(G, v); } } void DFS(MGraph G, int v) { printf("%3c", G.vex[v]); visited[v] = 1; int w = FirstAdjVex(G, v); while (w != -1) { if (visited[w] == 0)DFS(G, w); w = NextAdjVex(G, v, w); } } //BFS遍歷 typedef struct QNode { ElemType data; struct QNode *next; }QNode, *QueuePtr; //定義隊列的指針類型為QueuePtr,定義隊列結點內存空間類型為QNode typedef struct { QueuePtr front; //front為頭指針,指向頭結點。Q.front->next指針存在頭結點的指針域(即其存着首結點的地址),是頭結點的指針,指向首結點 QueuePtr rear; }LinkQueue; //定義隊列結點類型為LinkQueue Status InitQueue(LinkQueue &Q) { Q.front = (QNode*)malloc(sizeof(QNode)); if (!Q.front)return ERROR; Q.front->next = NULL; Q.rear = Q.front; return OK; } Status EnQueue(LinkQueue &Q, ElemType e) //入隊 { QueuePtr p; p = (QNode*)malloc(sizeof(QNode)); //生成新結點p if (!p)return ERROR; p->next = NULL; //新結點的指針p->next置空 p->data = e; //新結點暫存e Q.rear->next = p; //隊尾結點的指針Q.rear->next指向新結點p Q.rear = p; //隊尾指針Q.rear指向p return OK; } Status DeQueue(LinkQueue &Q, ElemType &e) //出隊 { QueuePtr p; if (Q.rear == Q.front) //確保隊列有首結點 return ERROR; p = Q.front->next; //指針p暫存被刪結點(首結點)的地址 Q.front->next = p->next; //頭結點的指針Q.front->next指向首結點的下一結點 e = p->data; if (Q.front->next == Q.rear) //判斷原隊列是否只有首結點 Q.rear = Q.front; free(p);//清空 return OK; } bool EmptyQueue(LinkQueue Q) //判空 { if (Q.front == Q.rear)return true; else return false; } void BFS(MGraph G) { printf("廣度優先遍歷為:\n"); int v; LinkQueue Q; InitQueue(Q); for (v = 0; v<G.vnum; v++) //初始化 visited[v] = 0; for (v = 0; v<G.vnum; v++) { if (visited[v] == 1)continue; printf("%3c", G.vex[v]); visited[v] = 1; EnQueue(Q, G.vex[v]); while (EmptyQueue == 0) { int v; ElemType e; DeQueue(Q, e); v = Location(G, e); int w = FirstAdjVex(G, v); while (w != -1) { w = NextAdjVex(G, v, w); if (visited[w] = 1)continue; printf("%3c", G.vex[w]); EnQueue(Q, G.vex[w]); visited[w] = 1; } } } } int main() { MGraph G; ElemType v[] = "abcdef"; //頂點數組 ElemType a[] = "ab,ac,ad,be,ce,df"; //邊數組 CreateGraph(G, 6, 6, v, a); Print(G); DFSTraverse(G); printf("\n"); BFS(G); printf("\n"); system("pause"); return 0; }//
鄰接表完整代碼:

#include<stdio.h> #include<malloc.h> #define OK 1 #define ERROR 0 #define MAXNUM 10 typedef int Status; typedef char ElemType; typedef struct ANode { int adjvex; //鄰接點域 struct ANode *next; //鄰接點指針域 }ANode; //ANode為單鏈表的指針類型 typedef struct { ElemType data; ANode *firstarc; //定義單鏈表的頭指針為firstarc }VNode; //VNode為頂點數組元素的類型 typedef struct { int vnum,anum; //頂點數,邊數 VNode vex[MAXNUM]; //頂點集 }ALGraph; //ALGraph鄰接表類型 int Location(ALGraph G, ElemType e) { int v; for (v = 0; v<G.vnum; v++) if (G.vex[v].data == e)return v; return -1; } Status CreatGraph(ALGraph &G, int vnum, int anum, ElemType v[], ElemType a[]) { int k, t = 0; G.vnum = vnum; G.anum = anum; for (k = 0; k<G.vnum; k++) { G.vex[k].data = v[k]; G.vex[k].firstarc = NULL;//易忘記 } for (k = 0; k<G.anum; k++) { ElemType m, n; ANode *p1, *p2, *p3; int p, q; m = a[t++]; n = a[t++]; t++; p = Location(G, m); q = Location(G, n); p1 = (ANode*)malloc(sizeof(ANode)); if (p1 == NULL)return ERROR; p1->adjvex = q; p1->next = NULL; if (G.vex[p].firstarc == NULL) G.vex[p].firstarc = p1; else { p3 = G.vex[p].firstarc; while (p3->next) p3 = p3->next; p3->next = p1; } p2 = (ANode*)malloc(sizeof(ANode)); if (!p2)return ERROR; p2->adjvex = p; p2->next = NULL; if (G.vex[q].firstarc == NULL) G.vex[q].firstarc = p2; else { p3 = G.vex[p].firstarc; while (p3->next) p3 = p3->next; p3->next = p2; } } return OK; } int FirstAdjVex(ALGraph G, int v) { if (v<0 || v >= G.vnum)return -1; if (G.vex[v].firstarc != NULL) return G.vex[v].firstarc->adjvex; return -1; } int NextAdjVex(ALGraph G, int v, int w) { ANode *p; p = G.vex[v].firstarc; if (v<0 || v >= G.vnum)return -1; if (w<0 || w >= G.vnum)return -1; while (p&&p->adjvex != w) p = p->next; if (p != NULL || p->next != NULL) return p->next->adjvex; return -1; } //DFS int visited[MAXNUM]; void DFS(ALGraph G, int v); void DFSTraverse(ALGraph G) { printf("深度遍歷為:\n"); int v; for (v = 0; v<G.vnum; v++) visited[v] = 0; for (v = 0; v<G.vnum; v++) if (visited[v] == 0)DFS(G, v); printf("\n"); } void DFS(ALGraph G, int v) { int w; printf("%3c", G.vex[v].data); visited[v] = 1; w = FirstAdjVex(G, v); while (w != -1) { if (visited[w] == 0)DFS(G, w); w = NextAdjVex(G, v, w); } } //BFS遍歷-鏈隊列 typedef struct QNode { ElemType data; struct QNode *next; }QNode, *QueuePtr; typedef struct { QueuePtr front; QueuePtr rear; }LinkQueue; Status InitQueue(LinkQueue &Q) { Q.front = (QNode*)malloc(sizeof(QNode)); if (!Q.front)return ERROR; Q.front->next = NULL; Q.rear = Q.front; return OK; } //入隊 Status EnQueue(LinkQueue &Q, ElemType e) { QueuePtr p; p = (QNode*)malloc(sizeof(QNode)); if (!p)return ERROR; p->next = NULL; p->data = e; Q.rear->next = p; Q.rear = p; return OK; } //出隊 Status DeQueue(LinkQueue &Q, ElemType &e) { QueuePtr p; if (Q.rear == Q.front) return ERROR; p = Q.front->next; Q.front->next = p->next; if (Q.front->next == Q.rear) Q.rear = Q.front; e = p->data; free(p);//清空 return OK; } //判空 bool EmptyQueue(LinkQueue Q) { if (Q.front == Q.rear)return true; else return false; } //BFS void BFS(ALGraph G) { printf("廣度優先遍歷為:\n"); int v; LinkQueue Q; InitQueue(Q); for (v = 0; v<G.vnum; v++)//初始化 visited[v] = 0; for (v = 0; v<G.vnum; v++) { if (visited[v] == 1)continue; printf("%3c", G.vex[v].data); visited[v] = 1; EnQueue(Q, G.vex[v].data); while (EmptyQueue == 0) { int v; ElemType e; DeQueue(Q, e); v = Location(G, e); int w = FirstAdjVex(G, v); while (w != -1) { w = NextAdjVex(G, v, w); if (visited[w] = 1)continue; printf("%3c", G.vex[w].data); EnQueue(Q, G.vex[w].data); visited[w] = 1; } } } } int main() { ALGraph G; ElemType v[] = "abcdef"; ElemType a[] = "ab,ac,ad,be,ce,df"; CreatGraph(G, 6, 6, v, a); DFSTraverse(G); BFS(G); getchar(); return 0; }