图的遍历——深度优先搜索+广度优先搜索
一:圖的遍歷——深度優先搜索
在本文其他內容中只是大體概括了主要的圖論內容,更加詳細的代碼實現及算法分析在此給出。
?
深度優先搜索(DFS)類似樹的先序遍歷。
假設初始狀態是圖中所有頂點未曾被訪問,則深度優先搜索可從圖中某個頂點發,訪問此頂點,然后依次從v的未被訪問的鄰接點出發深度優先遍歷圖,直至圖中階和V有路徑相通的頂點都被訪問到;若此時圖中尚有頂點未被訪問則另選圖中一個未被訪問的頂點作起始點,重復上述過程,直至圖中所有頂點都被訪問到為止。
以下圖為例,假設從V1出發開始搜索,在訪問了V1之后選擇鄰接點V2,因為V2未被訪問,
則從V2出發進行搜索。依次類推,接著從V4\V8V5出發進行搜索。在訪問了V5之后,由于V5的鄰接點都已被訪問,則搜索回到V1。此時由于V1的另一個鄰接點未被訪問,則搜索又從V1到V3,再繼續進行下去。由此,得到的頂點訪問序列為:
V1->V2->V4->V8->V5->V3->V6->V7;
顯然,這是一個遞歸的過程。為了在遍歷過程中便于區分頂點是否已被訪問需附設訪問標志數組visited[n-1]其初值為false一?且某個頂點被訪問,則其相應的分量置"true"。
?
?
具體代碼用C語言實現如下:
#include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<limits.h> /* INT_MAX等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<io.h> /* eof() */#include<math.h> /* floor(),ceil(),abs() */#include<process.h> /* exit() *//* 函數結果狀態代碼 */#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1typedef int Status; /* Status是函數的類型,其值是函數結果狀態代碼,如OK等 */typedef int Boolean; /* Boolean是布爾類型,其值是TRUE或FALSE */#define MAX_NAME 5 /* 頂點字符串的最大長度 */typedef int InfoType;typedef char VertexType[MAX_NAME]; /* 字符串類型 *//* 圖的鄰接表存儲表示 */#define MAX_VERTEX_NUM 20typedef enum{DG,DN,AG,AN}GraphKind; /* {有向圖,有向網,無向圖,無向網} */typedef struct ArcNode{int adjvex; /* 該弧所指向的頂點的位置 */struct ArcNode *nextarc; /* 指向下一條弧的指針 */InfoType *info; /* 網的權值指針) */}ArcNode; /* 表結點 */typedef struct{VertexType data; /* 頂點信息 */ArcNode *firstarc; /* 第一個表結點的地址,指向第一條依附該頂點的弧的指針 */}VNode,AdjList[MAX_VERTEX_NUM]; /* 頭結點 */typedef struct{AdjList vertices;int vexnum,arcnum; /* 圖的當前頂點數和弧數 */int kind; /* 圖的種類標志 */}ALGraph;Boolean visited[MAX_VERTEX_NUM]; /* 訪問標志數組(全局量) */void(*VisitFunc)(char* v); /* 函數變量(全局量) */void DFS(ALGraph G,int v){ /* 從第v個頂點出發遞歸地深度優先遍歷圖G。算法7.5 */int w;VertexType v1,w1;strcpy(v1,*GetVex(G,v));visited[v]=TRUE; /* 設置訪問標志為TRUE(已訪問) */VisitFunc(G.vertices[v].data); /* 訪問第v個頂點 */for(w=FirstAdjVex(G,v1);w>=0;w=NextAdjVex(G,v1,strcpy(w1,*GetVex(G,w))))if(!visited[w])DFS(G,w); /* 對v的尚未訪問的鄰接點w遞歸調用DFS */}void DFSTraverse(ALGraph G,void(*Visit)(char*)){ /* 對圖G作深度優先遍歷。算法7.4 */int v;VisitFunc=Visit; /* 使用全局變量VisitFunc,使DFS不必設函數指針參數 */for(v=0;v<G.vexnum;v++)visited[v]=FALSE; /* 訪問標志數組初始化 */for(v=0;v<G.vexnum;v++)if(!visited[v])DFS(G,v); /* 對尚未訪問的頂點調用DFS */printf("\n");}?
?
?
?
二:廣度優先搜索
廣度優先搜索(BFS)遍歷類似于樹的層序遍歷。
假設從圖中某頂點V出發,在訪問了V之后依次訪問V的未曾訪問過的鄰接點,然后分別從這些鄰接點出發依次訪問它們的鄰接點并使“先被訪問的頂點的鄰接點”先于“后被訪問的頂點的鄰接點”被訪問,直至圖中所有已被訪問的頂點的鄰接點都被訪問到。若此時圖中尚有頂點未被訪問,則另選圖中一個未曾被訪問的頂點作起始點,重復上述過程,直至圖中所有頂點都被訪問到為止。換句話說廣度優先搜索遍歷圖的過程是以V為起始點,由近至遠.依次訪問和V有路徑相通且路徑長度為1,2,...的頂點。
對上圖得到的頂點訪問序列為V1->V2->V3->V4->V5->V6->V7->v8。?
具體代碼用C語言實現如下:
typedef int QElemType; /* 隊列類型 *//* c3-2.h 單鏈隊列--隊列的鏈式存儲結構 */typedef struct QNode{QElemType data;struct QNode *next;}QNode,*QueuePtr;typedef struct{QueuePtr front,rear; /* 隊頭、隊尾指針 */}LinkQueue; /* bo3-2.c 鏈隊列(存儲結構由c3-2.h定義)的基本操作(9個) */Status InitQueue(LinkQueue *Q){ /* 構造一個空隊列Q */(*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));if(!(*Q).front)exit(OVERFLOW);(*Q).front->next=NULL;return OK;}Status DestroyQueue(LinkQueue *Q){ /* 銷毀隊列Q(無論空否均可) */while((*Q).front){(*Q).rear=(*Q).front->next;free((*Q).front);(*Q).front=(*Q).rear;}return OK;}Status ClearQueue(LinkQueue *Q){ /* 將Q清為空隊列 */QueuePtr p,q;(*Q).rear=(*Q).front;p=(*Q).front->next;(*Q).front->next=NULL;while(p){q=p;p=p->next;free(q);}return OK;}Status QueueEmpty(LinkQueue Q){ /* 若Q為空隊列,則返回TRUE,否則返回FALSE */if(Q.front==Q.rear)return TRUE;elsereturn FALSE;}int QueueLength(LinkQueue Q){ /* 求隊列的長度 */int i=0;QueuePtr p;p=Q.front;while(Q.rear!=p){i++;p=p->next;}return i;}Status GetHead_Q(LinkQueue Q,QElemType *e) /* 避免與bo2-6.c重名 */{ /* 若隊列不空,則用e返回Q的隊頭元素,并返回OK,否則返回ERROR */QueuePtr p;if(Q.front==Q.rear)return ERROR;p=Q.front->next;*e=p->data;return OK;}Status EnQueue(LinkQueue *Q,QElemType e){ /* 插入元素e為Q的新的隊尾元素 */QueuePtr p=(QueuePtr)malloc(sizeof(QNode));if(!p) /* 存儲分配失敗 */exit(OVERFLOW);p->data=e;p->next=NULL;(*Q).rear->next=p;(*Q).rear=p;return OK;}Status DeQueue(LinkQueue *Q,QElemType *e){ /* 若隊列不空,刪除Q的隊頭元素,用e返回其值,并返回OK,否則返回ERROR */QueuePtr p;if((*Q).front==(*Q).rear)return ERROR;p=(*Q).front->next;*e=p->data;(*Q).front->next=p->next;if((*Q).rear==p)(*Q).rear=(*Q).front;free(p);return OK;}Status QueueTraverse(LinkQueue Q,void(*vi)(QElemType)){ /* 從隊頭到隊尾依次對隊列Q中每個元素調用函數vi()。一旦vi失敗,則操作失敗 */QueuePtr p;p=Q.front->next;while(p){vi(p->data);p=p->next;}printf("\n");return OK;}void BFSTraverse(ALGraph G,void(*Visit)(char*)){/*按廣度優先非遞歸遍歷圖G。使用輔助隊列Q和訪問標志數組visited。算法7.6 */int v,u,w;VertexType u1,w1;LinkQueue Q;for(v=0;v<G.vexnum;++v)visited[v]=FALSE; /* 置初值 */InitQueue(&Q); /* 置空的輔助隊列Q */for(v=0;v<G.vexnum;v++) /* 如果是連通圖,只v=0就遍歷全圖 */if(!visited[v]) /* v尚未訪問 */{visited[v]=TRUE;Visit(G.vertices[v].data);EnQueue(&Q,v); /* v入隊列 */while(!QueueEmpty(Q)) /* 隊列不空 */{DeQueue(&Q,&u); /* 隊頭元素出隊并置為u */strcpy(u1,*GetVex(G,u));for(w=FirstAdjVex(G,u1);w>=0;w=NextAdjVex(G,u1,strcpy(w1,*GetVex(G,w))))if(!visited[w]) /* w為u的尚未訪問的鄰接頂點 */{visited[w]=TRUE;Visit(G.vertices[w].data);EnQueue(&Q,w); /* w入隊 */}}}printf("\n");}歡迎關注本博主
?
總結
以上是生活随笔為你收集整理的图的遍历——深度优先搜索+广度优先搜索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DeepMind最新研究:如何将「大语言
- 下一篇: [ACL2020]Generalizin