圖的遍歷之DSF深度優先演算法6.2.1(網路整理)
阿新 • • 發佈:2019-02-09
圖的遍歷之深度優先演算法虛擬碼描述(和樹的前序遍歷相似,實際上樹可以看成特殊的圖:N個頂點有N-1條邊,不曾在迴路!即樹是圖連通中最少邊的情況)
圖片來自網路
如上圖:
深度優先遍歷:
先選取一個頂點訪問它,然後深度優先遍歷它的每個未訪問的鄰接點
#include<stdlib.h> #include<stdbool.h> #include<stdio.h> #define MaxVertexNum 100 /* 最大頂點數設為100 */ typedef int Vertex; /* 用頂點下標表示頂點,為整型 */ typedef int WeightType; /* 邊的權值設為整型 */ typedef char DataType; /* 頂點儲存的資料型別設為字元型 */ bool Visited[MaxVertexNum]; /* 邊的定義 */ typedef struct ENode *PtrToENode; struct ENode{ Vertex V1, V2; /* 有向邊<V1, V2> */ WeightType Weight; /* 權重 */ }; typedef PtrToENode Edge; /* 鄰接點的定義 */ typedef struct AdjVNode *PtrToAdjVNode; struct AdjVNode{ Vertex AdjV; /* 鄰接點下標 */ WeightType Weight; /* 邊權重 */ PtrToAdjVNode Next; /* 指向下一個鄰接點的指標 */ }; /* 頂點表頭結點的定義 */ typedef struct Vnode{ PtrToAdjVNode FirstEdge;/* 邊表頭指標 */ DataType Data; /* 存頂點的資料 */ /* 注意:很多情況下,頂點無資料,此時Data可以不用出現 */ } AdjList[MaxVertexNum]; /* AdjList是鄰接表型別 */ /* 圖結點的定義 */ typedef struct GNode *PtrToGNode; struct GNode{ int Nv; /* 頂點數 */ int Ne; /* 邊數 */ AdjList G; /* 鄰接表 */ }; typedef PtrToGNode LGraph; /* 以鄰接表方式儲存的圖型別 */ LGraph CreateGraph( int VertexNum ) { Vertex V; /* 初始化一個有VertexNum個頂點但沒有邊的圖 */ LGraph Graph=(LGraph)malloc(sizeof(struct GNode)); Graph->Nv=VertexNum; Graph->Ne=0; /* 初始化鄰接表頭指標 */ /* 注意:這裡預設頂點編號從0開始,到(Graph->Nv - 1) */ for (V=0; V<Graph->Nv; V++) Graph->G[V].FirstEdge = NULL; return Graph; } void InsertEdge( LGraph Graph, Edge E ) { PtrToAdjVNode NewNode; /* 插入邊 <V1, V2> */ /* 為V2建立新的鄰接點 */ NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode)); NewNode->AdjV = E->V2; NewNode->Weight = E->Weight; /* 將V2插入V1的表頭 */ NewNode->Next = Graph->G[E->V1].FirstEdge; Graph->G[E->V1].FirstEdge = NewNode; /* 若是無向圖,還要插入邊 <V2, V1> */ /* 為V1建立新的鄰接點 */ NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode)); NewNode->AdjV = E->V1; NewNode->Weight = E->Weight; /* 將V1插入V2的表頭 */ NewNode->Next = Graph->G[E->V2].FirstEdge; Graph->G[E->V2].FirstEdge = NewNode; } LGraph BuildGraph() { LGraph Graph; Edge E; Vertex V; int Nv, i; scanf("%d", &Nv); /* 讀入頂點個數 */ Graph = CreateGraph(Nv); /* 初始化有Nv個頂點但沒有邊的圖 */ scanf("%d", &(Graph->Ne)); /* 讀入邊數 */ if ( Graph->Ne != 0 ) { /* 如果有邊 */ E = (Edge)malloc( sizeof(struct ENode) ); /* 建立邊結點 */ /* 讀入邊,格式為"起點 終點 權重",插入鄰接矩陣 */ for (i=0; i<Graph->Ne; i++) { scanf("%d %d %d", &E->V1, &E->V2, &E->Weight); /* 注意:如果權重不是整型,Weight的讀入格式要改 */ InsertEdge( Graph, E ); } free(E); } /* 如果頂點有資料的話,讀入資料 */ for (V=0; V<Graph->Nv; V++) scanf(" %c", &(Graph->G[V].Data)); return Graph; } /* 鄰接表儲存的圖 - DFS */ void Visit( Vertex V ) { printf("正在訪問頂點%d\n", V); } /* Visited[]為全域性變數,已經初始化為false */ void DFS( LGraph Graph, Vertex V, void (*PVisit)(Vertex) ) { /* 以V為出發點對鄰接表儲存的圖Graph進行DFS搜尋 */ PtrToAdjVNode W; (*PVisit)( V ); /* 訪問第V個頂點 */ Visited[V] = true; /* 標記V已訪問 */ for( W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 對V的每個鄰接點W->AdjV */ if ( !Visited[W->AdjV] ) /* 若W->AdjV未被訪問 */ DFS( Graph, W->AdjV, PVisit ); /* 則遞迴訪問之 */ } int main(){ for(int i=0;i<MaxVertexNum;i++) Visited[i]=false;//初始化為false LGraph Graph=BuildGraph(); DFS(Graph,0,Visit); return 0; }
用棧模擬#include<stdlib.h> #include<stdbool.h> #include<stdio.h> #define MaxVertexNum 100 /* 最大頂點數設為100 */ #define INFINITY 65535 /* ∞設為雙位元組無符號整數的最大值65535*/ typedef int Vertex; /* 用頂點下標表示頂點,為整型 */ typedef int WeightType; /* 邊的權值設為整型 */ typedef char DataType; /* 頂點儲存的資料型別設為字元型 */ bool Visited[MaxVertexNum]; /* 邊的定義 */ typedef struct ENode *PtrToENode; struct ENode{ Vertex V1, V2; /* 有向邊<V1, V2> */ WeightType Weight; /* 權重 */ }; typedef PtrToENode Edge; /* 圖結點的定義 */ typedef struct GNode *PtrToGNode; struct GNode{ int Nv; /* 頂點數 */ int Ne; /* 邊數 */ WeightType G[MaxVertexNum][MaxVertexNum]; /* 鄰接矩陣 */ DataType Data[MaxVertexNum]; /* 存頂點的資料 */ /* 注意:很多情況下,頂點無資料,此時Data[]可以不用出現 */ }; typedef PtrToGNode MGraph; /* 以鄰接矩陣儲存的圖型別 */ MGraph CreateGraph( int VertexNum ) { /* 初始化一個有VertexNum個頂點但沒有邊的圖 */ Vertex V, W; MGraph Graph; Graph = (MGraph)malloc(sizeof(struct GNode)); /* 建立圖 */ Graph->Nv = VertexNum; Graph->Ne = 0; /* 初始化鄰接矩陣 */ /* 注意:這裡預設頂點編號從0開始,到(Graph->Nv - 1) */ for (V=0; V<Graph->Nv; V++) for (W=0; W<Graph->Nv; W++) if(V==W) Graph->G[V][W]=0; else Graph->G[V][W] = INFINITY; return Graph; } void InsertEdge( MGraph Graph, Edge E ) { /* 插入邊 <V1, V2> */ Graph->G[E->V1][E->V2] = E->Weight; /* 若是無向圖,還要插入邊<V2, V1> */ Graph->G[E->V2][E->V1] = E->Weight; } MGraph BuildGraph() { MGraph Graph; Edge E; Vertex V; int Nv, i; scanf("%d", &Nv); /* 讀入頂點個數 */ Graph = CreateGraph(Nv); /* 初始化有Nv個頂點但沒有邊的圖 */ scanf("%d", &(Graph->Ne)); /* 讀入邊數 */ if ( Graph->Ne != 0 ) { /* 如果有邊 */ E = (Edge)malloc(sizeof(struct ENode)); /* 建立邊結點 */ /* 讀入邊,格式為"起點 終點 權重",插入鄰接矩陣 */ for (i=0; i<Graph->Ne; i++) { scanf("%d %d %d", &E->V1, &E->V2, &E->Weight); /* 注意:如果權重不是整型,Weight的讀入格式要改 */ InsertEdge( Graph, E ); } free(E); } /* 如果頂點有資料的話,讀入資料 */ for (V=0; V<Graph->Nv; V++) scanf(" %c", &(Graph->Data[V])); return Graph; } void Visit( Vertex V ) { printf("正在訪問頂點%d\n", V); } /* Visited[]為全域性變數,已經初始化為false */ void DFS( MGraph Graph, Vertex V, void (*PVisit)(Vertex) ){ /* 以V為出發點對鄰接表儲存的圖Graph進行DFS搜尋 */ (*PVisit)( V ); /* 訪問第V個頂點 */ Visited[V] = true; /* 標記V已訪問 */ for(Vertex W=0;W<Graph->Nv;W++) if(!Visited[W]&&Graph->G[V][W]!=INFINITY&&V!=W) /* 對V的每個未被訪問de鄰接點*/ DFS(Graph,W,PVisit); } int main(){ for(int i=0;i<MaxVertexNum;i++) Visited[i]=false;//初始化為false MGraph Graph=BuildGraph(); DFS(Graph,0,Visit); return 0; }