圖的建立以及深度與廣度優先遍歷C/C++
阿新 • • 發佈:2019-01-24
一、圖的儲存結構
圖有幾種最常見的儲存結構:鄰接矩陣、鄰接表和十字連結串列。
下面僅以鄰接表表示法進行圖的操作
鄰接表:
鄰接表(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) ;
}