標籤:圖 圖的遍曆 圖的深度和廣度遍曆
本文為原創,轉載請註明出處:http://blog.csdn.net/j903829182/article/details/38174029
/*圖的遍曆方法主要有兩種:一種是深度優先遍曆,一種是廣度優先遍曆。圖的深度優先遍曆類同於樹的先根遍曆,圖的廣度遍曆類同樹的層次遍曆 一:連通圖的深度優先遍曆演算法 圖的深度優先遍曆演算法是遍曆時深度優先的演算法,即在圖的所有鄰接頂點中,每次都在訪問當前頂點後,首先訪問當前頂點的 第一個鄰接頂點。 連通圖的深度優先遍曆遞迴演算法如下: 1.訪問頂點v並標記頂點v已訪問。 2.尋找頂點v的第一個鄰接頂點w。 3.若頂點v的鄰接頂點w存在,則繼續執行,否則演算法結束。 4.若頂點w尚未被訪問,則深度優先遍曆遞迴訪問頂點w。 5.尋找頂點v的w的鄰接頂點的下一個鄰接w,轉到步驟3 二:連通圖的廣度優先遍曆演算法 圖的廣度優先遍曆演算法是一個分層搜尋的過程,廣度優先演算法遍曆是指,從指定頂點開始,按照到該頂點路徑長度由短到長的順序,訪問圖 中的其餘頂點。 連通圖的廣度優先遍曆演算法如下: 1.訪問初始頂點v並標記頂點v為已訪問. 2.頂點v入隊列。 3.若隊列非空,則繼續執行,否則演算法結束 4.出隊列取得隊頭頂點u。 5.尋找頂點u的第一個鄰接頂點w。 6.若頂點u的鄰接頂點w不存在,則轉到步驟3,否則迴圈執行: a.若頂點w尚未被訪問,則訪問頂點w並標記頂點w為已訪問; b.頂點w入隊列; c.尋找頂點u的w鄰接頂點後的下一個鄰接頂點w,轉到步驟6 三:非連通圖的遍曆演算法 對於非連通圖,從圖的任意一個頂點開始深度或廣度優先遍曆一定可以訪問圖中的所有頂點。但對於非連通圖, 從圖的任意一個初始頂點開始深度或廣度優先遍曆,並不能訪問圖中的所有頂點,此時只能訪問和初始頂點連通的那些頂點。 但是,對於非連通圖,可以依次把每個頂點都作為一次初始頂點進行深度優先遍曆或廣度優先遍曆,並根據每個頂點的訪問標誌 來判斷該頂點是否已經訪問過。若尚未訪問過,則訪問之,否則跳過該頂點。這樣就一定可以訪問非連通圖中的多有頂點。*///鄰接矩陣儲存結構操作的實現#include<stdio.h>#include<malloc.h>#define MaxSize 100 //定義元素的大小typedef char DataType; //定義一個類型#define MaxVertices 10 //定義頂點的最大值#define MaxWeight 10000 //定義無窮大的具體值#define MaxQueueSize 15typedef int DataType1;typedef struct{DataType1 queue[MaxQueueSize];int rear;//隊列指標int front;//對頭指標int count;//計數器}SeqCQueue;//初始化void QueueInitiate(SeqCQueue *q){//初始化順序迴圈隊列qq->count=0;//定義初始計數器q->rear=0;//定義初始隊尾指標下標q->front=0;//定義初始對頭指標標}//非空int QueueNotEmpty(SeqCQueue q){//判斷順序迴圈隊列q非空否,非空則返回1,否則返回0if(q.count!=0){return 1;}else{return 0;}}//入隊列int QueueAppend(SeqCQueue *q,DataType1 x){//把資料元素值x插入順序迴圈隊列q的隊尾,成功則返回1,失敗返回0if(q->count>0&&q->rear==q->front){//隊滿判斷printf("隊列已滿無法插入!!\n");return 0;}else{q->queue[q->rear]=x;//資料元素x插入隊尾q->rear=(q->rear+1)%MaxQueueSize;//隊尾指標加1q->count++;//計數器加1return 1;//返回1}}//出隊列int QueueDelete(SeqCQueue *q,DataType1 *d){//刪除順序迴圈隊列q的隊頭元素並賦給d,成功返回1,失敗則返回0if(q->count==0){//對空判斷printf("隊列已空無資料元素出隊列!!\n");return 0;}else{*d=q->queue[q->front];//取對頭元素存入d中q->front=(q->front+1)%MaxQueueSize;//對頭指標加1q->count--;//計算機減一return 1;}}//取對頭資料元素int QueueGet(SeqCQueue q,DataType1 *d){//取順序迴圈隊列q的當前對頭元素並賦給d,成功則返回1,失敗則返回0if(q.count==0){printf("隊列已空,無資料元素可以取!!\n");return 0;}else{*d=q.queue[q.front];return 1;}}typedef struct{ //定義一個結構體 DataType list[MaxSize]; int size; //結構體元素的大小}SeqList; //結構體的對象typedef struct{SeqList Vertices;//存放頂點的順序表int edge[MaxVertices][MaxVertices];//存放邊的鄰接矩陣int numOfEdges;//邊的條數}AdjMGraph;typedef struct{int row;//行下標int col;//列下標int weight;//權值}RowColWeight;//邊資訊結構體//初始化void initiate(SeqList *L){ L->size=0;//定義初始化元素個數}//求當前元素的個數int getLength(SeqList L){return L.size;//返回長度}//插入資料元素int insertData(SeqList *L,int i,DataType x){//在順序表L的第i(0<=i<=size)個位置前插入資料元素x//插入成功返回1,出人失敗返回0 int j; if(L->size>=MaxSize){ printf("順序表已滿,無法插入!!\n"); return 0; }else if(i<0||i>L->size){ printf("插入的位置不合法,不在指定的範圍,參數i不合法!\n"); return 0; }else{ //從後向前一致移動資料,為插入做準備 for(j=L->size;j>i;j--){ L->list[j]=L->list[j-1]; } L->list[i]=x; L->size++; return 1; }}//刪除資料int deleteData(SeqList *L,int i,DataType *x){ //刪除順序表中位置為i的資料i>=0&&i<=size-1,把資料儲存到x中//刪除成功返回1,否則返回0int j;if(L->size<=0){ printf("順序表已空無資料元素可刪!\n");return 0;}else if(i<0||i>L->size-1){ printf("參數i不合法,不能刪除!\n");return 0;}else{*x=L->list[i];for(j=i+1;j<=L->size-1;j++){//從前往後一次前移 L->list[j-1]=L->list[j];}L->size--;//資料元素減一return 1;}}//取出資料元素int getData(SeqList L,int i,DataType *x){ if(i<0||i>L.size-1){printf("參數i不合法,不能刪除!\n");return 0;}else{ *x=L.list[i];return 1;}}//初始化有n個頂點的順序表和鄰接矩陣void InitiateG(AdjMGraph *g,int n){//初始化int i,j;for(i=0;i<n;i++){for(j=0;j<n;j++){if(i==j){g->edge[i][j]=0;}else{g->edge[i][j]=MaxWeight;//MaxWeight表示無窮大}}}g->numOfEdges=0;//邊的條數置為0initiate(&g->Vertices);//順序表初始化}//插入頂點void InsertVertex(AdjMGraph *g,DataType vertex){//在圖G中插入頂點vertexinsertData(&g->Vertices,g->Vertices.size,vertex);//順序表尾插入}//插入邊void InsertEdge(AdjMGraph *g,int v1,int v2,int weight){//在圖中插入邊<v1,v2>,邊<v1,v2>的權為weightif(v1<0||v1>=g->Vertices.size||v2<0||v2>=g->Vertices.size){printf("參數v1或v2越界出錯!!!\n");return ;}g->edge[v1][v2]=weight;g->numOfEdges++;}//刪除邊void DeleteEdge(AdjMGraph *g,int v1,int v2){//在G圖中刪除邊<v1,v2>if(v1<0||v1>=g->Vertices.size||v2<0||v2>=g->Vertices.size){printf("參數v1或v2越界出錯!!!\n");return ;}if(g->edge[v1][v2]==MaxWeight||v1==v2){printf("該邊不存在!!!\n");return;}g->edge[v1][v2]=MaxWeight;g->numOfEdges--;}//取第一個鄰接頂點int GetFirstVex(AdjMGraph g,int v){//在圖G中尋找序號為v的頂點的第一個鄰接頂點//如果這樣的頂點存在,則返回該鄰接頂點的序號,否則返回-1int col;if(v<0||v>=g.Vertices.size){printf("參數v1越界出錯!!!\n");return -1;}for(col=0;col<g.Vertices.size;col++){if(g.edge[v][col]>0&&g.edge[v][col]<MaxWeight){return col;}}return -1;}//取下一個鄰接頂點int GetNextVex(AdjMGraph g,int v1,int v2){//在圖中尋找v1頂點的鄰接頂點v2的下一個鄰接頂點//如果這樣的鄰接頂點存在,則返回該鄰接頂點的序號;否則返回-1//v1和v2都是相應的頂點的序號int col;if(v1<0||v1>g.Vertices.size||v2<0||v2>=g.Vertices.size){printf("參數v1或v2越界出錯!!!\n");return -1;}for(col=v2+1;col<g.Vertices.size;col++){if(g.edge[v1][col]>0&&g.edge[v1][col]<MaxWeight){return col;}}return -1;}void CreatGraph(AdjMGraph *g,DataType V[],int n,RowColWeight E[],int e){//在圖中插入n個頂點資訊V和e條邊資訊Eint i,k;InitiateG(g,n);//d頂點順序表初始化for(i=0;i<n;i++){InsertVertex(g,V[i]);//插入頂點}for(k=0;k<e;k++){InsertEdge(g,E[k].row,E[k].col,E[k].weight);//插入邊}}void Visit(DataType item){//定義訪問操作函數 printf("%c ",item);}//連通圖的深度優先函數void DepthFSearch(AdjMGraph g,int v,int visited[], void Visit(DataType item)){//連通圖G以v為初始頂點的訪問操作作為Visit()的深度優先遍曆//數組visited標記了相應頂點是否已經訪問過,0表示未訪問,1表示已經訪問int w; Visit(g.Vertices.list[v]);//訪問頂點vvisited[v]=1;//置已訪問標誌w=GetFirstVex(g,v);//取第一個鄰接頂點while(w!=-1){if(!visited[w]){DepthFSearch(g,w,visited,Visit);//遞迴}w=GetNextVex(g,v,w);}}//非連通圖的深度優先遍曆函數void DepthFirstSearch(AdjMGraph g,void Visit(DataType item)){//非連通圖G的訪問操作作為Visit()的深度優先遍曆int i;int *visited=(int *)malloc(sizeof(int)*g.Vertices.size);for(i=0;i<g.Vertices.size;i++){visited[i]=0;//訪問標誌初始均為0}for(i=0;i<g.Vertices.size;i++){if(!visited[i]){DepthFSearch(g,i,visited,Visit);//以每個頂點為初始頂點進行調用}} free(visited);}//連通圖的廣度優先遍曆函數void BrodFSearch(AdjMGraph g,int v,int visited[], void Visit(DataType item)){//連通圖G以v為初始頂點訪問操作為Visit廣度優先遍曆//數組visited標記了相應頂點是否已訪問過,0表示未訪問,1表示已訪問DataType1 u,w;SeqCQueue queue; Visit(g.Vertices.list[v]);//訪問頂點vvisited[v]=1;//置已訪問標誌 QueueInitiate(&queue);//隊列初始化 QueueAppend(&queue,v);//初始頂點v入隊列 while(QueueNotEmpty(queue)){QueueDelete(&queue,&u);//出隊列w=GetFirstVex(g,u);//取頂點u的第一個鄰接頂點while(w!=-1){//鄰接頂點w存在時if(!visited[w]){//若沒有訪問過Visit(g.Vertices.list[w]);//訪問頂點wvisited[w]=1;//置已訪問標誌QueueAppend(&queue,w);//頂點w入隊列}w=GetNextVex(g,u,w);//取下一個鄰接頂點}}}//非連通圖的廣度優先遍曆函數如下:void BroadFirstSearch(AdjMGraph g,void Visit(DataType item)){//非連通圖G訪問操作為Visit()的廣度優先遍曆int i;int *visited=(int *)malloc(sizeof(int)*g.Vertices.size); for(i=0;i<g.Vertices.size;i++){visited[i]=0;//訪問標誌初始均為0}for(i=0;i<g.Vertices.size;i++){if(!visited[i]){BrodFSearch(g,i,visited,Visit);//以每一個頂點為初始頂點進行調用}}free(visited);}void main(){AdjMGraph g;DataType a[]={'A','B','C','D','E'};RowColWeight rcw[]={{0,1,10},{0,4,20},{1,3,30},{2,1,40},{3,2,50}};int n=5,e=5;int i,j;CreatGraph(&g,a,n,rcw,e);//建立圖 printf("深度優先遍曆序列為:");DepthFirstSearch(g,Visit); printf("\n廣度優先遍曆序列為:"); BroadFirstSearch(g,Visit);printf("\n");}