圖的存儲結構與操作--C語言實現


圖(graph)是一種比樹結構還要復雜的數據結構,它的術語,存儲方式,遍歷方式,用途都比較廣,所以如果想要一次性完成所有的代碼,那代碼會非常長。所以,我將分兩次來完成圖的代碼。這一次,我會完成圖的五種存儲結構的創建鄰接矩陣存儲鄰接表存儲十字鏈表存儲鄰接多重表存儲邊集數組存儲),兩種遍歷方式深度優先遍歷廣度優先遍歷)。與樹結構一樣,圖結構的遍歷也需要借助隊列來協助實現。

 1 #include<stdio.h>
 2 #include<malloc.h>
 3 typedef char VertexType;        //頂點類型
 4 typedef int EdgeType;            //權值類型
 5 #define MAXVEX 100                //最大頂點數
 6 #define INFINITY 65535            //無限大
 7 #define TURE 1
 8 #define FALSE 0
 9 typedef int Boolean;  10 Boolean visited[MAXVEX];            //記錄訪問過的結點數組
 11 
 12 #define MAXSIZE 100                            //隊列最大空間
 13 typedef int QElemType;                        //隊列中元素類型
 14 typedef int Status;                            //返回值類型
 15 #define OK 1                                //操作成功
 16 #define ERROR 0                                //操作失敗
 17 
 18 typedef struct                                //隊列結點結構
 19 {  20     QElemType date[MAXSIZE];                //結點元素
 21     int front;                                //隊頭
 22     int rear;                                //隊尾
 23 }SqQueue;  24 
 25 /*隊列的初始化*/
 26 Status InitQue(SqQueue *Q)  27 {  28     Q->front = 0;                            //隊頭指向0
 29     Q->rear = 0;                            //隊尾指向0
 30     return OK;  31 }  32 
 33 /*隊列的入隊操作*/
 34 Status EnQueue(SqQueue *Q, QElemType e)  35 {  36     if((Q->rear + 1) % MAXSIZE == Q->front)                //判斷隊列是否已滿
 37         return ERROR;  38     Q->date[Q->rear] = e;                                //隊尾賦值為e
 39     Q->rear = (Q->rear + 1) % MAXSIZE;                    //隊尾后移
 40     return OK;  41 }  42 
 43 /*隊列的出隊操作*/
 44 Status DeQueue(SqQueue *Q, QElemType *e)  45 {  46     if(Q->front == Q->rear)                                //判斷隊列是否為空
 47         return ERROR;  48     *e = Q->date[Q->front];                                //將隊頭元素取出
 49     Q->front = (Q->front + 1) % MAXSIZE;                //隊頭后移
 50     return OK;  51 }  52 
 53 /*獲取隊列的長度*/
 54 int LengthQue(SqQueue Q)  55 {  56     return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;  57 }  58 
 59 //鄰接矩陣結構體
 60 typedef struct                    
 61 {  62     VertexType adList[MAXVEX];            //聲明頂點數組
 63     EdgeType arc[MAXVEX][MAXVEX];        //聲明權值數組
 64     int numVerexes,numEdges;            //頂點數,邊數
 65 }Graph;  66 
 67 //鄰接表結構體
 68 typedef struct EdgeNode                //邊表結構體
 69 {  70     int adjSub;                        //存儲邊表的下標  71 // EdgeType weight; //權重
 72     struct EdgeNode *next;            //指向下一個相鄰頂點的指針
 73 }EdgeNode;  74 
 75 typedef struct VertexNode            //頂點結構體
 76 {  77     VertexType date;                //頂點內容
 78     EdgeNode *firstEdge;            //指向頂點第一個鄰接點
 79 }GraphList[MAXVEX];  80 
 81 typedef struct                        //鄰接表結構體
 82 {  83     GraphList graphList;            //頂點數組
 84     int numVerexes, numEdges;        //頂點數,邊數
 85 }AjaGraph;  86 
 87 //十字鏈表結構體
 88 typedef struct Orthogonal            //邊表結構體
 89 {  90     int tailVex;                    //當前頂點下標
 91     int headVex;                    //弧尾頂點下標
 92     struct Orthogonal *tailLink;    //指向入度弧的弧尾
 93     struct Orthogonal *headLink;    //指向出度弧的弧頭
 94 }Orthogonal;  95 
 96 typedef struct                        //頂點結構體
 97 {  98     VertexType date;                //頂點內容
 99     Orthogonal *firstin;            //指向第一個弧頭為自己的點
100     Orthogonal *firstout;            //指向第一個弧尾為自己的點
101 }Orthogonal_Node[MAXVEX]; 102 
103 typedef struct
104 { 105     Orthogonal_Node orth_Node;        //聲明結點數組
106     int numVertexes,numEdges;        //頂點數量,邊數量
107 }OrthGraph;                            //十字鏈表圖結構 108 
109 //邊集數組結構體
110 typedef struct                        //邊結構體
111 { 112     int iVex;                        //頂點位置
113     int jVex;                        //頂點位置
114     EdgeType weight;                //權重
115 }EdgeArray[MAXVEX]; 116 
117 typedef struct                        //圖結構體
118 { 119     VertexType VexterList[MAXVEX];    //頂點數組
120     EdgeArray EdgeList;                //邊數組
121     int numVexteres, numEdges;        //頂點數量,邊數量
122 }EdgeListArray;                        //邊集數組圖結構 123 
124 //鄰接多重表
125 typedef struct EdgeList_multiple            //邊表結點
126 { 127     int iVex;                                    //當前頂點下標
128     int jVex;                                    //終點下表
129     struct EdgeList_multiple *iLink;                    //指向與頂點i有相同起點的結點
130     struct EdgeList_multiple *jLink;                    //指向與頂點j有相同終點的結點
131 }EdgeList_multiple; 132 
133 typedef struct
134 { 135     VertexType date;                        //頂點數據
136     EdgeList_multiple *firstEdge;            //指向頂點的第一個鄰接點
137 }Vexs; 138 
139 typedef struct
140 { 141     Vexs vexs[MAXVEX];                                //建立頂點數組
142     int numVexes;                            //頂點數量
143     int numEdges;                            //邊的數量
144 }MultipleGraph; 145 
146 //鄰接多重表創建圖結構
147 int CreatGraphMultiple(MultipleGraph *G) 148 { 149     int i,j,k; 150     printf("請輸入頂點數i與邊的數量j:"); 151     scanf("%d,%d",&G->numVexes,&G->numEdges); 152     EdgeList_multiple *em; 153  getchar(); 154     for(i = 0; i < G->numVexes; i++) 155  { 156         printf("請輸入第%d個頂點:",i); 157         scanf("%c", &G->vexs[i].date); 158  getchar(); 159  } 160     for(k = 0; k < G->numEdges; k++) 161  { 162         printf("請輸入邊的起點i與終點j的下標:"); 163         scanf("%d,%d",&i,&j); 164         em = (EdgeList_multiple *)malloc(sizeof(EdgeList_multiple));        //創建新結點空間
165         em->iVex = i; 166         em->jVex = j; 167         em->iLink = G->vexs[i].firstEdge; 168         G->vexs[i].firstEdge = em; 169         em->jLink = G->vexs[j].firstEdge; 170         G->vexs[j].firstEdge = em; 171  } 172     return 1; 173 } 174 
175 //鄰接矩陣創建圖結構
176 int CreatGraph(Graph *G) 177 { 178     int i,j,k,w; 179     printf("請輸入結點數i,邊數j:"); 180     scanf("%d,%d",&G->numVerexes,&G->numEdges);        //寫入頂點數和邊數
181     for(i = 0; i < G->numVerexes; i++)                    //初始化頂點數組
182  { 183         printf("請輸入第%d個頂點:",i); 184         scanf("%c",&G->adList[i]); 185  getchar(); 186  } 187     for(i = 0; i < G->numVerexes; i++)                    //初始化權值矩陣
188         for(j = 0; j < G->numVerexes; j++) 189             G->arc[i][j] = INFINITY; 190     for(k = 0; k<G->numEdges; k++)                        //寫入權值
191  { 192         printf("請輸入需要添加權值的下標i和下標j,及其權值w:"); 193         scanf("%d,%d,%d", &i, &j, &w); 194         G->arc[i][j] = w; 195         G->arc[j][i] = G->arc[i][j];                    //無向圖的對稱性
196  } 197     return 1; 198 } 199 
200 //鄰接表創建圖結構
201 int CreatAjaGraph(AjaGraph *G) 202 { 203     int i, j, k; 204     char a; 205     EdgeNode *e;                                //聲明邊表新結點
206     printf("請輸入頂點i和邊數j:"); 207     scanf("%d, %d", &G->numVerexes, &G->numEdges);        //寫入頂點數與邊數
208  getchar(); 209     for(i = 0; i < G->numVerexes; i++)                    //初始化頂點數組
210  { 211         printf("請輸入第%d個結點:",i); 212         scanf("%c",&G->graphList[i].date); 213  getchar(); 214         printf("%c\n", a); 215         G->graphList[i].firstEdge = NULL;                //頂點數組的指針域指向空
216  } 217     for(k = 0; k < G->numEdges; k++)                    //構建邊表
218  { 219         printf("請輸入鄰接點Vi與Vj的下標:"); 220         scanf("%d,%d", &i, &j); 221         e = (EdgeNode *)malloc(sizeof(EdgeNode));        //創建新結點空間
222         e->adjSub = j;                                    //新結點的數據域為j
223         e->next = G->graphList[i].firstEdge;            //新結點指針域指向頂點指針域
224         G->graphList[i].firstEdge = e;                    //頂點指針域指向新結點
225 
226         e = (EdgeNode *)malloc(sizeof(EdgeNode));        //因為是無向圖
227         e->adjSub = i;                                    //同時為i操作
228         e->next = G->graphList[j].firstEdge; 229         G->graphList[j].firstEdge = e; 230  } 231     
232     return 1; 233 } 234 
235 //十字鏈表結構創建圖結構
236 int CreatOrthGraph(OrthGraph *G) 237 { 238     int i,j,k; 239     Orthogonal *e; 240     printf("請輸入頂點數量i和邊數量j:"); 241     scanf("%d,%d", &G->numVertexes, &G->numEdges);        //寫入頂點數和邊數
242     for(i = 0; i < G->numVertexes; i++)                    //對頂點數組初始化
243  { 244         printf("請輸入第%d個結點:",i); 245         scanf("%c",&G->orth_Node[i].date);                    //輸入頂點內容
246  getchar(); 247         G->orth_Node[i].firstin = NULL;                    //將入邊表指向空
248         G->orth_Node[i].firstout = NULL;                //將出邊表指向空
249  } 250     for(k = 0; k < G->numEdges; k++)                    //構建邊表
251  { 252         printf("請輸入起點i與終點j的下標:"); 253         scanf("%d,%d", &i, &j); 254         e = (Orthogonal *)malloc(sizeof(Orthogonal));    //創建新結點空間
255         e->tailVex = i;                                    //當前結點等於i
256         e->headVex = j;                                    //弧尾等於j
257         e->tailLink = G->orth_Node[i].firstout;            //入度指針等於頂點入度指針
258         G->orth_Node[i].firstout = e;                    //頂點位置i的firstout指向e 
259         e->headLink = G->orth_Node[j].firstin;            //出度指針等於頂點出度指針 
260         G->orth_Node[j].firstin = e;                    //頂點位置j的firstout指向e
261  } 262     return 1; 263 } 264 
265 //邊集數組創建圖結構
266 int CreatGraph(EdgeListArray *G) 267 { 268     int i, j, w; 269     printf("請輸入頂點數量i與邊的數量j:"); 270     scanf("%d,%d", &G->numVexteres, &G->numEdges);        //寫入頂點數量與邊數量
271     for(i = 0; i < G->numVexteres; i++)                    //構建頂點數組
272  { 273         printf("請輸入第%d個結點:",i); 274         scanf("%c",&G->VexterList[i]); 275  } 276     for(i = 0; i < G->numEdges; i++)                    //構建邊數組
277  { 278         printf("請輸入頂點i與頂點j及其權重w:"); 279         scanf("%d,%d", &i, &j, &w); 280         G->EdgeList[i].iVex = i;                        //這里的i只是邊數組的下標,與頂點數組無關
281         G->EdgeList[i].jVex = j; 282         G->EdgeList[i].weight = w; 283  } 284     return 1; 285 } 286 
287 //遍歷鄰接矩陣結構
288 void PrintfGraph(Graph G) 289 { 290     int i,j; 291     for(i = 0; i < G.numVerexes; i++) 292         for(j = 0; j < G.numVerexes; j++) 293             if(G.arc[i][j] != INFINITY && i < j) 294                 printf("頂點: %d , %d, 權重: %d\n", i, j, G.arc[i][j]); 295 } 296 
297 //鄰接表深度優先遍歷
298 void PrintDeepthAjaGraph(AjaGraph G, int i)            //遞歸函數
299 { 300     visited[i] = TURE;                                //將此頂點記為訪問過
301     printf("%c\n", G.graphList[i].date);            //打印當前頂點
302     EdgeNode *ag;                                    //創建頂點指針
303     ag = G.graphList[i].firstEdge;                    //將此指針賦值為當前頂點的邊表第一個結點
304     while(ag)                                        //只要ag不為空
305  { 306         if(!visited[ag->adjSub])                    //如果當前邊表第一個結點不為空
307             PrintDeepthAjaGraph(G, ag->adjSub);        //遞歸
308         ag = ag->next;                                //否則ag賦值為ag的下一臨結點
309  } 310 } 311 
312 void Depth_first(AjaGraph G)                //深度優先遍歷函數
313 { 314     int j; 315     for(j = 0; j < G.numVerexes; j++)        //初始化記錄數組
316         visited[j] = FALSE; 317     for(j = 0; j < G.numVerexes; j++)        //遍歷頂點數組中的每一個頂點
318  { 319 // printf("當前結點是:%d, 其是否遍歷過 %d\n", j, visited[j]);
320         if(!visited[j])                        //如果當前結點沒被訪問過
321             PrintDeepthAjaGraph(G, j);        //調用遞歸函數
322  } 323 } 324 
325 //鄰接表廣度優先搜索
326 void BFs(AjaGraph G) 327 { 328     int j; 329     SqQueue Q;            //創建隊Q
330     InitQue(&Q);        //初始化隊列
331     for(j = 0; j < G.numVerexes; j++)            //初始化記錄數組
332         visited[j] = FALSE; 333     EdgeNode *ag;                                //創建邊表指針
334     visited[0] = TURE;                            //將第一個頂點記為訪問過
335     printf("%c\n", G.graphList[0].date);        //打印第一個頂點
336     EnQueue(&Q, 0);                                //將第一個頂點入隊
337     while(Q.front != Q.rear)                    //只要隊列不為空
338  { 339         DeQueue(&Q, &j);                        //將當前頂點出隊
340         ag = G.graphList[j].firstEdge;            //ag賦值為當前結點的第一個邊表結點
341         while(ag && !visited[ag->adjSub])        //ag不為空且ag未被訪問過
342  { 343             visited[ag->adjSub] = TURE;            //將ag記為訪問過
344             printf("%c\n", G.graphList[ag->adjSub].date);    //打印ag
345             EnQueue(&Q, ag->adjSub);            //將ag入隊
346             ag = ag->next;                        //ag賦值為ag的下一鄰接表結點
347  } 348  } 349 } 350 
351 void main() 352 { 353  Graph G1; 354  AjaGraph G2; 355  OrthGraph G3; 356  MultipleGraph G4; 357  EdgeListArray G5; 358     while(true) 359  { 360         int flag = 0; 361         printf("請選擇對圖的操作:\n"); 362         printf("1.鄰接矩陣存儲創建\n"); 363         printf("2.鄰接表存儲創建\n"); 364         printf("3.十字鏈表存儲創建\n"); 365         printf("4.鄰接多重表創建\n"); 366         printf("5.邊集數組創建\n"); 367         printf("6.遍歷鄰接矩陣圖結構\n"); 368         printf("7.鄰接表深度優先遍歷\n"); 369         printf("8.遍歷線索化二叉樹\n"); 370         printf("9.退出\n"); 371         int a; 372         scanf("%d", &a); 373         switch(a) 374  { 375             case 1: 376                 flag = 0; 377                 flag = CreatGraph(&G1); 378                 if(flag) 379                     printf("創建成功\n"); 380                 else
381                     printf("創建失敗\n"); 382                 break; 383             case 2: 384                 flag = 0; 385                 flag = CreatAjaGraph(&G2); 386                 if(flag) 387                     printf("創建成功\n"); 388                 else
389                     printf("創建失敗\n"); 390                 break; 391             case 3: 392                 flag = 0; 393                 flag = CreatOrthGraph(&G3); 394                 if(flag) 395                     printf("創建成功\n"); 396                 else
397                     printf("創建失敗\n"); 398                 break; 399             case 4: 400                 flag = 0; 401                 flag = CreatGraphMultiple(&G4); 402                 if(flag) 403                     printf("創建成功\n"); 404                 else
405                     printf("創建失敗\n"); 406                 break; 407             case 5: 408                 flag = 0; 409                 CreatGraph(&G5); 410                 if(flag) 411                     printf("創建成功\n"); 412                 else
413                     printf("創建失敗\n"); 414                 break; 415             case 6: 416  PrintfGraph(G1); 417                 break; 418             case 7: 419  Depth_first(G2); 420                 break; 421             case 8: 422  BFs(G2); 423                 break; 424             case 9: 425                 return; 426             default: 427                 printf("選擇錯誤\n"); 428                 break; 429  } 430  } 431 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM