C語言數據結構圖的創建與遍歷實驗示例

一、 實驗目的

理解圖的基本概念,掌握圖的存儲結構,實現圖的深度優先搜索遍歷算法與廣度優先搜索遍歷算法。

二、 實驗內容

利用鄰接矩陣描述示例圖,編寫程序輸出示例圖的深度優先搜索和廣度優先搜索的遍歷序列。

具體步驟如下:

  • 將圖的鄰接矩陣描述為一個二維數組,並將該數組定義為全局變量,以便數據的傳遞;
  • 定義一個隊列,在廣度優先搜索時,該隊列存儲已被訪問的路徑長度為1,2,…的頂點;
  • 定義訪問函數visit()、深度優先搜索函數DFS()和廣度優先搜索函數BFS();
  • 主函數實現各函數的調用。

三、 實驗工具

Dev-C++

四、 實驗代碼

//Authors:xiaobei
#include<stdio.h>
#include<stdlib.h>
#define MaxInt 32767
#define MVNum 100
typedef char VerTexType;
typedef int ArcType;
//定義圖結構
typedef struct{
 VerTexType vexs[MVNum];
 ArcType arcs[MVNum][MVNum];
 int vexnum,arcnum;
}AMGraph;
//定義輔助鏈隊
typedef struct QNode{
 char data;
 struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
 QueuePtr front;
 QueuePtr rear;
}LinkQueue;
//定義全局輔助數組visited[MVNum]
int visited[MVNum];
//函數返回定點下標
int LocateVex(AMGraph G,char v){
 int i;
 for(i=0;i<G.vexnum;i++)
  if(G.vexs[i]==v)
   return i;
  return -1;
}
//函數訪問並輸出頂點,返回下標
int visit(AMGraph G,char v){
 int i;
 for(i=0;i<G.vexnum;i++)
  if(v==G.vexs[i])
   printf("%c",v);
 return LocateVex(G,v);
}
//函數創建無向圖,以鄰接矩陣形式
int CreateUDN(AMGraph &G){
 int i,j,k,v1,v2,w;
 printf("[輸入總頂點數和邊數:]\n>>>");
 scanf("%d %d",&G.vexnum,&G.arcnum);
 for(i=0;i<G.vexnum;i++)
 {
  getchar();
  printf("[依次輸入各頂點的信息:]\n>>>");
  scanf("%c",&G.vexs[i]);
 }
 for(i=0;i<G.vexnum;i++)
  for(j=0;j<G.vexnum;j++)
   G.arcs[i][j] = MaxInt;
 for(k=0;k<G.arcnum;k++){
  getchar();
  printf("[輸入一條邊依附的頂點及權值:]\n>>>"); 
  scanf("%c %c %d",&v1,&v2,&w);
  i = LocateVex(G,v1);
  j = LocateVex(G,v2);
  G.arcs[i][j]=w;
  G.arcs[j][i]=G.arcs[i][j];
 }
 return 1;
}
//函數深度遍歷連通圖
void DFS_AM(AMGraph G,char v){
 int w,u;
 u = visit(G,v);
 visited[u] = 1;
 for(w=0;w<G.vexnum;w++){
  if((G.arcs[u][w]<MaxInt) && (!visited[w]))
   DFS_AM(G,G.vexs[w]);
 }
}
//函數初始化鏈隊
void InitQueue(LinkQueue &Q){
 Q.front = Q.rear = (QNode*)malloc(sizeof(QNode));
 Q.front->next=NULL;
}
//函數數據進隊
void EnQueue(LinkQueue &Q,char e){
 QueuePtr p;
 p = (QNode*)malloc(sizeof(QNode));
 p->data = e;
 p->next = NULL;
 Q.rear->next=p;
 Q.rear = p;
}
//函數數據出隊
void DeQueue(LinkQueue &Q,char &e){
 QueuePtr p;
 if(Q.front==Q.rear);
 else
 {
  p = Q.front->next;
  e = p->data;
  Q.front->next = p->next;
  if(Q.rear==p)
   Q.rear=Q.front;
  free(p);
 }
}
//函數判斷鏈隊是否為空
int QueueEmpty(LinkQueue Q){
 if(Q.front==Q.rear)
  return 1;
 else
  return 0;
}
//函數返回頂點下一個鄰接點下標
int FirstAdjVex(AMGraph G,int c){
 int j;
 for(j=0;j<G.vexnum;j++)
  if(G.arcs[c][j]<MaxInt && visited[j]==0)
   return j;
  return -1;
}
//函數返回頂點下一個相對鄰接點下標
int NextAdjVex(AMGraph G,int c,int w){
 int j;
 for(j=0;j<G.vexnum;j++)
  if(G.arcs[c][j]<MaxInt && visited[j]==0)
   return j;
  return -1;
}
//函數廣度遍歷連通圖
void BFS_AM(AMGraph G,char v){
 int c,w,i;
 char u;
 LinkQueue Q;
 c = visit(G,v);
 visited[c] = 1;
 InitQueue(Q);
 EnQueue(Q,v);
 while(!QueueEmpty(Q)){
  DeQueue(Q,u);
  c = LocateVex(G,u);
  for(w=FirstAdjVex(G,c);w>=0;w=NextAdjVex(G,c,w))
  {
   if(!visited[w]){
    i = visit(G,G.vexs[w]);
    visited[i] = 1;
    EnQueue(Q,G.vexs[w]);
   }
  }
 }
}
//菜單打印
void Menu(){
 printf("\n————————菜單————————\n");
 printf("\n1.創建圖結構;\n");
 printf("\n2.深度遍歷(DFS);\n");
 printf("\n3.廣度遍歷(BFS);\n");
 printf("\n0.退出;\n");
 printf("\n——————————————————\n");
 printf("[請輸入你的選擇:]\n>>>");
}
//主函數
int main(){
 int i,user;
 char v;
 AMGraph G;
 while(1){
  Menu();
  scanf("%d",&user);
  switch(user){
  case 1:{
   CreateUDN(G);
   break;
  }
  case 2:{
   //初始化輔助數組
   for(i=0;i<G.vexnum;i++)
    visited[i] = 0;
   printf("[請輸入遍歷開始的頂點:]\n>>>");
   getchar();
   scanf("%c",&v);
   DFS_AM(G,v);
   break;
  }
  case 3:{
   //初始化輔助數組
   for(i=0;i<G.vexnum;i++)
    visited[i] = 0;
   printf("[請輸入遍歷開始的頂點:]\n>>>");
   getchar();
   scanf("%c",&v);
   BFS_AM(G,v);
   break;
  }
  case 0:{
   exit(0);
   break;
  }
  }
 }
 return 0;
}

五、 實驗結果

六、總結與思考

  • 無向圖的鄰接矩陣是對稱的,有向圖鄰接矩陣可能不對稱。
  • 深度優先搜索類似於棧結構的出棧於入棧過程,模擬遞歸,其實遞歸也是通過堆棧的形式實現的。
  • 廣度遍歷是非遞歸過程,借助隊列來實現。
  • 輔助數組需要在全局使用,在主函數外定義。
  • DFS與BFS空間復雜度都是O(n),鄰接矩陣時間復雜度都是O(n2),鄰接表時間復雜度為O(n+e)。

鄰接矩陣示意圖:

以上就是C語言數據結構圖的創建與遍歷實驗示例的詳細內容,更多關於C語言數據結構圖的創建遍歷的資料請關註WalkonNet其它相關文章!

推薦閱讀: