一.深度優先遍歷是連通圖的一種遍歷策略。其基本思想如下:
設x是當前被訪問頂點,在對x做過訪問標記後,選擇一條從x出發的未檢測過的邊(x,y)。若發現頂點y已訪問過,則重新選擇另一條從x出發的未檢測過的邊,否則沿邊(x,y)到達未曾訪問過的y,對y訪問並將其標記為已訪問過;然後從y開始搜索,直到搜索完從y出發的所有路徑,即訪問完所有從y出發可達的頂點之後,才回溯到頂點x,並且再選擇一條從x出發的未檢測過的邊。上述過程直至從x出發的所有邊都已檢測過為止。
例如下圖中:
1.從0開始,首先找到0的關聯頂點3 2.由3出發,找到1;由1出發,沒有關聯的頂點。 3.回到3,從3出發,找到2;由2出發,沒有關聯的頂點。 4.回到4,出4出發,找到1,因為1已經被訪問過了,所以不訪問。 所以最後順序是0,3,1,2,4 二.廣度優先遍歷是連通圖的一種遍歷策略。其基本思想如下:
1、從圖中某個頂點V0出發,並訪問此頂點;
2、從V0出發,訪問V0的各個未曾訪問的鄰接點W1,W2,…,Wk;然後,依次從W1,W2,…,Wk出發訪問各自未被訪問的鄰接點;
3、重復步驟2,直到全部頂點都被訪問為止。
例如下圖中: 1.從0開始,首先找到0的關聯頂點3,4 2.由3出發,找到1,2;由4出發,找到1,但是1已經遍歷過,所以忽略。 3.由1出發,沒有關聯頂點;由2出發,沒有關聯頂點。 所以最後順序是0,3,4,1,2 三.下面以此無向圖為例,實現深度優先遍歷和廣度優先遍歷: 實現代碼如下:
/** 鄰接表深度優先遍歷和廣度優先遍歷 **/ #include<stdio.h> #include<stdlib.h> #define MaxVex 255 #define TRUE 1 #define FALSE 0 typedef char VertexType; //頂點類型 typedef int Bool; Bool visited[MaxVex]; //全局數組,記錄圖中節點訪問狀態 typedef struct EdgeNode { //邊表節點 int adjvex; //該鄰接點在頂點數組中的下標 struct EdgeNode *next; //鏈域 指向下一個鄰接點 }EdgeNode; typedef struct VertexNode { //頭節點 VertexType data; //頂點信息 EdgeNode *firstedge; //邊表頭指針(指向第一條依附於該頂點的弧的指針) }VertexNode,AdjList[MaxVex]; //頂點數組(結構體數組) typedef struct Graph{ AdjList adjList; int numVertexes,numEdges; //圖中當前的結點數以及邊數 }Graph,*GraphAdjList; /** 隊列定義及相關操作(廣度遍歷會用到此循環隊列) **/ typedef struct LoopQueue{ int data[MaxVex]; int front,rear; }LoopQueue,*Queue; //隊列結構 void initQueue(Queue &Q){ Q->front=Q->rear=0; } Bool QueueEmpty(Queue &Q){ if(Q->front == Q->rear){ return TRUE; }else{ return FALSE; } } Bool QueueFull(Queue &Q){ if((Q->rear+1)%MaxVex == Q->front){ return TRUE; }else{ return FALSE; } } /** * 隊尾插入元素 */ void EnQueue(Queue &Q,int e){ if(!QueueFull(Q)){ Q->data[Q->rear] = e; Q->rear = (Q->rear+1)%MaxVex; } } /** * 隊頭刪除元素 */ void DeQueue(Queue &Q,int *e){ if(!QueueEmpty(Q)){ *e = Q->data[Q->front]; Q->front = (Q->front+1)%MaxVex; } } /*************************************************/ /** * 建立圖的鄰接表結構(此處以無向圖為例) */ void CreateALGraph(GraphAdjList &G){ int i, j, k; if(G==NULL){ G = (GraphAdjList)malloc(sizeof(Graph)); } printf("輸入圖的結點數以及邊數: "); scanf("%d%d",&G->numVertexes,&G->numEdges); fflush(stdin); printf("===========================\n"); printf("輸入各個頂點的數據:\n"); for (i=0; i<G->numVertexes; ++i){ printf("頂點%d: ",i+1); scanf("%c", &(G->adjList[i].data)); G->adjList[i].firstedge = NULL; fflush(stdin); } printf("===========================\n"); for (k=0; k<G->numEdges; ++k){ printf("輸入(vi,vj)上的頂點序號: "); scanf("%d%d",&i,&j); EdgeNode *ptrEdgeNode = (EdgeNode*)malloc(sizeof(EdgeNode)); ptrEdgeNode->adjvex = j; ptrEdgeNode->next = G->adjList[i].firstedge; G->adjList[i].firstedge = ptrEdgeNode; ptrEdgeNode = (EdgeNode*)malloc(sizeof(EdgeNode)); ptrEdgeNode->adjvex = i; ptrEdgeNode->next = G->adjList[j].firstedge; G->adjList[j].firstedge = ptrEdgeNode; } } void DFS(GraphAdjList &G, int i){ visited[i] = TRUE; printf("%c ", G->adjList[i].data); EdgeNode *p = G->adjList[i].firstedge; while(p){ if(!visited[p->adjvex]){ DFS(G,p->adjvex); //遞歸深度遍歷 } p= p->next; } } /** * 深度優先遍歷 */ void DFSTraverse(GraphAdjList &G){ int i; for (i=0; i<G->numVertexes; ++i){ visited[i] = FALSE; //初始化訪問數組visited的元素值為false } for (i=0; i<G->numVertexes; ++i){ if(!visited[i]){ //節點尚未訪問 DFS(G,i); } } } /** * 圖的廣度優先遍歷 */ void BFSTraverse(GraphAdjList &G){ int i; Queue Q = (Queue)malloc(sizeof(LoopQueue)); for (i=0; i<G->numVertexes; ++i){ visited[i] = FALSE; } initQueue(Q); for (i=0; i<G->numVertexes; ++i){ if(!visited[i]){ visited[i] = TRUE; printf("%c ", G->adjList[i].data); EnQueue(Q, i); while (!QueueEmpty(Q)){ DeQueue(Q, &i); EdgeNode *p = G->adjList[i].firstedge; while (p){ if (!visited[p->adjvex]){ visited[p->adjvex] = TRUE; printf("%c ", G->adjList[p->adjvex].data); EnQueue(Q, p->adjvex); } p = p->next; } } } } } /** * 程序入口 */ int main(){ GraphAdjList G = NULL; CreateALGraph(G); printf("\n圖的深度優先遍歷為: "); DFSTraverse(G); printf("\n圖的廣度優先遍歷為: "); BFSTraverse(G); printf("\n"); return 0; }
運行結果截圖: