1. 程式人生 > >圖的建立以及深度與廣度優先遍歷C/C++

圖的建立以及深度與廣度優先遍歷C/C++

一、圖的儲存結構
圖有幾種最常見的儲存結構:鄰接矩陣、鄰接表和十字連結串列。
下面僅以鄰接表表示法進行圖的操作
鄰接表:
鄰接表(Adjacency List)是一種順序儲存結構與鏈式儲存相結合的圖的儲存方法。鄰接表類似於樹的孩子連結串列表示法。就是對於圖G中的每個Vi,將所有鄰接於Vi的頂點Vj鏈成一個單鏈表,這個單鏈表就稱為頂點Vi的鄰接表,再將所有點的鄰接表表頭放到陣列中,就構成了圖的鄰接表。在鄰接表中有兩種節點結構,如下:
這裡寫圖片描述
鄰接表的表示形式如下:
這裡寫圖片描述
二、鄰接表的資料結構

typedef char VertexType ;
typedef struct node
{
    int
adjvex ; struct node *next ; //指向下一個鄰接節點域 } EdgeNode ; typedef struct vnode { VertexType vertex[3] ; //頂點域 EdgeNode *firstedge ; //邊表頭指標 } VertexNode ; typedef VertexNode AdjList[MaxVerNum] ; /* *定義以鄰接邊為儲存型別的圖 */ typedef struct { AdjList adjList ; //鄰接表 int n , e ; //頂點數與邊數 } ALGraph ;

三、建立無向圖的演算法

/*
 *建立無向圖的鄰接表儲存
 */
 void CreateALGraph(ALGraph *G)
 {
     int i , j , k ;
     EdgeNode *s ;
     printf("請輸入頂點數與邊數(輸入格式為:頂點數,邊數): ") ;
     scanf("%d,%d" , &G->n , &G->e) ;
     printf("請輸入頂點資訊(輸入格式為:頂點號<CR>):\n") ;
     for( i = 0 ; i < G->n ; i++)
     {
         scanf
("%s" , G->adjList[i].vertex) ; G->adjList[i].firstedge = NULL ; //將頂點的邊表頭指標設定為空 } printf("請輸入邊的資訊(輸入格式為:i,j):\n") ; for(k = 0 ; k < G->e ; k++) { scanf("%d,%d" , &i , &j) ; s = (VertexNode*)malloc(sizeof(VertexNode)) ; //邊上的第一個節點 s->adjvex = j ; s->next = G->adjList[i].firstedge ; G->adjList[i].firstedge = s ; //邊上的第二個節點 s = (VertexNode*)malloc(sizeof(VertexNode)) ; s->adjvex = i ; s->next = G->adjList[j].firstedge ; G->adjList[j].firstedge = s ; } }

四、進行無向圖的深度優先遍歷
思路:
假設初始狀態是圖中所有頂點未曾被訪問,則深度優先搜尋可以從圖中某個頂點v出發,訪問此頂點,然後訪問v的一個未被訪問的鄰接節點w1,接著再從w1出發,訪問w1的一個未被訪問過的鄰接節點w2,然後再從w2出發,訪問w2的一個未被訪問的鄰接頂點w3…如此下去深度優先遍歷圖,直至圖中所有和v有路徑相同的頂點都被訪問到;若此時途中尚有頂點未被訪問,則另選圖中另外一個未曾被訪問的頂點做起始節點,重複上述過程,直至途中所有節點都被訪問到為止。
演算法:

/*
 *進行圖的深度優先搜尋遍歷
 */
 void DFSAL(ALGraph *G , int i)
 {
     //以Vi為出發點對圖進行遍歷
     EdgeNode *p ;
     printf("visit vertex : %s \n" , G->adjList[i].vertex) ;
     visited[i] = 1 ;
     p = G->adjList[i].firstedge ;
     while(p)
     {
         if(!visited[p->adjvex])
         {
             DFSAL(G , p->adjvex) ;
         }
         p = p->next ;
     }
 }
 void DFSTraverseAL(ALGraph *G)
 {
     int i ;
     for(i = 0 ; i < G->n ; i++)
     {
         visited[i] = 0 ;
     }
     for(i = 0 ; i < G->n ; i++)
     {
         if(!visited[i])
         {
             DFSAL(G , i) ;
         }
     }
 }

五、進行圖的廣度優先遍歷
1、從圖中某個頂點V0出發,並訪問此頂點;
2、從V0出發,訪問V0的各個未曾訪問的鄰接點W1,W2,…,Wk;然後,依次從W1,W2,…,Wk出發訪問各自未被訪問的鄰接點;
3、重複步驟2,直到全部頂點都被訪問為止。
利用佇列進行訪問節點的記錄。
演算法:

/*
 *建立佇列的資料結構方便進行廣度優先遍歷
 */
typedef struct
{
    int data[MaxVerNum] ;
    int head , tail ; //隊頭與隊尾
} Quene ;
/*
  *進行廣度優先搜尋遍歷
  */
void BFSG(ALGraph *G , int k)
{
    int i , j ;
    Quene q ;
    EdgeNode *p ;
    q.head = 0 ;
    q.tail = 0 ; //進行佇列的初始化
    printf("visit vertex : %s \n" , G->adjList[k].vertex) ;
    visited[k] = 1 ;
    q.data[q.tail++] = k ;
    while(q.head  % (MaxVerNum - 1) != q.tail % (MaxVerNum - 1))
    {
        i = q.data[q.head++] ;
        p = G->adjList[i].firstedge ;
        while(p)
        {
            if(!visited[p->adjvex])
            {
                printf("visit vertex : %s \n" , G->adjList[p->adjvex].vertex) ;
                visited[p->adjvex] = 1 ;
                q.data[q.tail++] = p->adjvex ;
            }
            p = p->next ;
        }
    }
}
void BFSTraverseAL(ALGraph *G)
{
    int i ;
    for(i = 0 ; i < G->n ; i++)
    {
        visited[i] = 0 ;
    }
    for(i = 0 ; i < G->n ; i++)
    {
        if(!visited[i])
        {
            BFSG(G , i) ;
        }
    }
}

六、全部測試程式碼

/*
 *進行圖的遍歷,進行圖的深度遍歷與廣度遍歷
 */
#include<stdio.h>
#include<malloc.h>
#define MaxVerNum 100 /*定義最大節點數*/
int visited[MaxVerNum] ;
typedef char VertexType ;
typedef struct node
{
    int adjvex ;
    struct node *next ; //指向下一個鄰接節點域
} EdgeNode ;
typedef struct vnode
{
    VertexType vertex[3] ; //頂點域
    EdgeNode *firstedge ; //邊表頭指標
} VertexNode ;
typedef VertexNode AdjList[MaxVerNum] ;
/*
 *定義以鄰接邊為儲存型別的圖
 */
typedef struct
{
    AdjList adjList ; //鄰接表
    int n , e ; //頂點數與邊數
} ALGraph ;
/*
 *建立佇列的資料結構方便進行廣度優先遍歷
 */
typedef struct
{
    int data[MaxVerNum] ;
    int head , tail ; //隊頭與隊尾
} Quene ;
/*
 *建立無向圖的鄰接表儲存
 */
 void CreateALGraph(ALGraph *G)
 {
     int i , j , k ;
     EdgeNode *s ;
     printf("請輸入頂點數與邊數(輸入格式為:頂點數,邊數): ") ;
     scanf("%d,%d" , &G->n , &G->e) ;
     printf("請輸入頂點資訊(輸入格式為:頂點號<CR>):\n") ;
     for( i = 0 ; i < G->n ; i++)
     {
         scanf("%s" , G->adjList[i].vertex) ;
         G->adjList[i].firstedge = NULL ; //將頂點的邊表頭指標設定為空
     }
     printf("請輸入邊的資訊(輸入格式為:i,j):\n") ;
     for(k = 0 ; k < G->e ; k++)
     {
         scanf("%d,%d" , &i , &j) ;
         s = (VertexNode*)malloc(sizeof(VertexNode)) ;
         //邊上的第一個節點
         s->adjvex = j ;
         s->next = G->adjList[i].firstedge ;
         G->adjList[i].firstedge = s ;
         //邊上的第二個節點
         s = (VertexNode*)malloc(sizeof(VertexNode)) ;
         s->adjvex = i ;
         s->next = G->adjList[j].firstedge ;
         G->adjList[j].firstedge = s ;
     }
 }
/*
 *進行圖的深度優先搜尋遍歷
 */
 void DFSAL(ALGraph *G , int i)
 {
     //以Vi為出發點對圖進行遍歷
     EdgeNode *p ;
     printf("visit vertex : %s \n" , G->adjList[i].vertex) ;
     visited[i] = 1 ;
     p = G->adjList[i].firstedge ;
     while(p)
     {
         if(!visited[p->adjvex])
         {
             DFSAL(G , p->adjvex) ;
         }
         p = p->next ;
     }
 }
 void DFSTraverseAL(ALGraph *G)
 {
     int i ;
     for(i = 0 ; i < G->n ; i++)
     {
         visited[i] = 0 ;
     }
     for(i = 0 ; i < G->n ; i++)
     {
         if(!visited[i])
         {
             DFSAL(G , i) ;
         }
     }
 }
 /*
  *進行廣度優先搜尋遍歷
  */
void BFSG(ALGraph *G , int k)
{
    int i , j ;
    Quene q ;
    EdgeNode *p ;
    q.head = 0 ;
    q.tail = 0 ; //進行佇列的初始化
    printf("visit vertex : %s \n" , G->adjList[k].vertex) ;
    visited[k] = 1 ;
    q.data[q.tail++] = k ;
    while(q.head  % (MaxVerNum - 1) != q.tail % (MaxVerNum - 1))
    {
        i = q.data[q.head++] ;
        p = G->adjList[i].firstedge ;
        while(p)
        {
            if(!visited[p->adjvex])
            {
                printf("visit vertex : %s \n" , G->adjList[p->adjvex].vertex) ;
                visited[p->adjvex] = 1 ;
                q.data[q.tail++] = p->adjvex ;
            }
            p = p->next ;
        }
    }
}
void BFSTraverseAL(ALGraph *G)
{
    int i ;
    for(i = 0 ; i < G->n ; i++)
    {
        visited[i] = 0 ;
    }
    for(i = 0 ; i < G->n ; i++)
    {
        if(!visited[i])
        {
            BFSG(G , i) ;
        }
    }
}
 /*
  *進行圖的測試
  */
void main()
{
  ALGraph *G ;
  EdgeNode *p = NULL ;
  int i ;
  G = (ALGraph*)malloc(sizeof(ALGraph)) ;
  CreateALGraph(G) ;
  printf("進行深度優先遍歷\n") ;
  DFSTraverseAL(G) ;
  printf("進行廣度優先遍歷\n") ;
  BFSTraverseAL(G) ;
}