1. 程式人生 > >資料結構之圖(圖的基本操作)

資料結構之圖(圖的基本操作)

由於圖的基本操作的程式碼較多,我放到這一章來寫。圖可以用兩種方法來儲存,但是本人偏愛連結串列的表示方法,所以以下程式碼也都是是基於鄰接連結串列的儲存方式。

 1 /*
 2    以下儲存結構參考嚴蔚敏版資料結構,不懂的可以翻閱檢視  
 3 */
 4 const int UNDIGRAPH = 0;    //無向圖
 5 const int DIGRAPH    = 1;    //有向圖
 6 const int MAX_VERTEX_NUM = 20;
 7 
 8 typedef struct ArchNode
 9 {
10     int    vertexIndex;        //
該弧指向頂點在圖中頂點陣列的索引,對應vertexs[20]的下標 11 ArchNode *nextarc; //指向下一條弧的指標 12 InfoTypde info; //比如弧的權重 13 }ArchNode; 14 15 typedef struct Vertex 16 { 17 VertexType data; //頂點資訊 18 ArchNode *firstarc; //指向第一條弧的指標 19 }Vertex; 20 21 //這樣定義圖有個壞處,一旦定義好,圖中結點的個數就固定了! 22 typedef struct
Graph 23 { 24 Vertex *vertexs[MAX_VERTEX_NUM]; //儲存頂點的陣列,存放的是指向頂點的指標 25 int vexNum; //當前圖中的定點數 26 int arcNum;         //當前圖中的弧的個數 27 int kind;          //圖的種類,有向圖還是無向圖 28 }Graph;

//圖的建立

 1 /*
 2    初始條件:kind是圖的型別,目前有有向圖和無向圖 兩種.
 3    返回值   :無。---大部分函式都無返回值,是對圖的引用進行操作的
4 */ 5 void createGraph(Graph *&G,int kind) 6 { 7 if(G) G = NULL; 8 G = (Graph *)malloc(sizeof(struct Graph)); 9 assert(NULL != G); 10 for(int i = 0; i < MAX_VERTEX_NUM; ++i) 11 { 12 G->vertexs[i] = NULL; //初始化指向頂點的指標為NULL 13 } 14 G->kind = kind; //設定圖的種類 15 G->vexNum = 0; //初始化圖中頂點的個數 16 G->arcNum = 0; //初始化圖中弧的個數 17 }

//圖的銷燬

 1 /*
 2    初始條件:G存在
 3    返回值   :無。---大部分函式都無返回值,是對圖的引用進行操作的
 4 */
 5 void destoryGraph(Graph *&G)
 6 {
 7     ArchNode *cur,*next;
 8     if(NULL == G)
 9         return;
10     //遍歷頂點
11     for(int i = 0; i < G->vexNum; ++i)
12     {
13         if(!G->vertexs[i])
14             continue;
15         next = G->vertexs[i]->firstarc;
16         cur  = G->vertexs[i]->firstarc;
17         while(cur)
18         {
19             next = cur->nextarc;
20             free(cur);
21             cur = next;
22         }
23         G->vertexs[i]->firstarc = NULL;
24     }
25     free(G);
26     G = NULL;
27 }

//向圖中增加結點

 1 //向圖中增加結點
 2 /*
 3     初始條件:G存在,data是結點的資料值
 4 */
 5 void addVertexToGraph(Graph *&G,VertexType data)
 6 {
 7     if(G->vexNum >= MAX_VERTEX_NUM)
 8     {
 9         cout << "Too many vertex!" << endl;
10         return ;
11     }
12     for(int i = 0; i < G->vexNum; ++i)
13     {
14         if(!G->vertexs[i])
15             continue;
16         if(G->vertexs[i]->data == data)
17         {
18             cout << "Already exists!" << endl;
19             return;        //不允許重複            
20         }
21     }
22     Vertex *pVeterx;
23     pVeterx = (Vertex *)malloc(sizeof(struct Vertex));
24     pVeterx->data = data;
25     pVeterx->firstarc = NULL;
26     G->vertexs[G->vexNum] = pVeterx;
27     G->vexNum++;
28 }

//從圖中刪除一個結點

 1 void delVertexFromGraph(Graph *&G,VertexType data)
 2 {
 3     bool haveThisVertex = false;
 4     ArchNode *cur,*next,*temp,*pre;
 5     Vertex *anotherVertex;
 6     if(NULL == G)
 7         return;
 8     if(G->vexNum <= 0)
 9     {
10         cout << "Have no vertex!" << endl;
11         return ;
12     }
13     for(int i = 0; i < G->vexNum; ++i)
14     {
15         if(!G->vertexs[i])
16             continue;
17         if(G->vertexs[i]->data == data)
18         {
19             haveThisVertex = true;
20             //以下迴圈用來刪除頂點所指向的弧連結串列
21             next = cur = G->vertexs[i]->firstarc;
22             if(G->kind == DIGRAPH)    //如果是有向圖
23             {
24                 while(cur)
25                 {
26                     next = cur->nextarc;
27                     free(cur);
28                     G->arcNum --;    //弧的個數減一
29                     cur = next;
30                 }
31                 G->vertexs[i] = NULL;
32             }
33             else if(G->kind == UNDIGRAPH)    //如果是無向圖,這個麻煩點
34             {
35                 while(cur)
36                 {
37                     //找到待刪除的弧的另一個結點,將它的弧連結串列中指向被刪除結點的弧也刪掉
38                     anotherVertex = G->vertexs[cur->vertexIndex];    //找到待刪除弧對應的另一個結點
39                     temp = anotherVertex->firstarc,pre = NULL;
40                     while(temp)                                        //這個迴圈是為了刪除另一個結點中儲存弧資訊
41                     {
42                         if(temp->vertexIndex == i)
43                         {
44                             //如果是首節點
45                             if(NULL == pre)    //或者if(NULL == pre)
46                             {
47                                 anotherVertex->firstarc = temp->nextarc;
48                                 free(temp);
49                             }
50                             else
51                             {
52                                 pre->nextarc = temp->nextarc;
53                                 free(temp);
54                             }
55                             break;    //找到即停止迴圈
56                         }
57                         pre = temp;
58                         temp = temp->nextarc;
59                     }
60                     next = cur->nextarc;
61                     free(cur);
62                     G->arcNum --;    //弧的個數減一
63                     cur = next;
64                 }
65                 G->vertexs[i] = NULL;
66             }
67             for(int j = i; j < G->vexNum - 1; ++j)
68             {
69                 G->vertexs[j] = G->vertexs[j + 1];
70             }
71             G->vertexs[j] = NULL;    //
72             G->vexNum-- ;            //結點的個數減一
73             break;
74         }
75     }
76     if(!haveThisVertex)
77         cout << "沒有該結點!" << endl;
78 }
//從圖中查詢一個值為指定值的結點的索引
 1 //初始條件:G存在,data是指定結點的資料值
 2 int findVertexIndexInGraph(const Graph *G,VertexType data)
 3 {
 4     if(NULL == G)
 5         return -1;
 6     for(int i = 0; i < G->vexNum; ++i)
 7     {
 8         if(!G->vertexs[i])
 9             continue;
10         if(G->vertexs[i]->data == data)
11         {
12             return i;
13             break;
14         }
15     }
16     return -1;
17 }

//向圖中增加一條弧,有有向圖和無向圖之分

 1 //初始條件:G存在,指定起始點,和弧的權重
 2 void addArchToGraph(Graph *&G,VertexType startData,VertexType endData,InfoTypde weight = 0)
 3 {
 4     ArchNode *pArchNode,*cur;
 5     //先要找到start和end
 6     if(NULL == G)
 7         return;
 8     int startVertexIndex = findVertexIndexInGraph(G,startData);
 9     int endVertexIndex = findVertexIndexInGraph(G,endData);
10     cur = G->vertexs[startVertexIndex]->firstarc;
11     while(cur)
12     {
13         if(cur->vertexIndex == endVertexIndex)
14         {
15             cout << "Already have this arch!" << endl;
16             return ;
17         }
18         cur = cur->nextarc;
19     }
20     if(startVertexIndex >= 0 && endVertexIndex >= 0)
21     {
22         if(G->kind == DIGRAPH)                                            //如果是有向圖
23         {
24             pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode));    //建立一個弧結點
25             pArchNode->info = weight;
26             pArchNode->nextarc = NULL;
27             pArchNode->vertexIndex = endVertexIndex;
28             cur = G->vertexs[startVertexIndex]->firstarc;
29             if(NULL == cur)
30             {
31                 G->vertexs[startVertexIndex]->firstarc = pArchNode;
32             }
33             else
34             {
35                 while(cur->nextarc)
36                 {
37                     cur = cur->nextarc;
38                 }
39                 cur->nextarc = pArchNode;
40             }
41             G->arcNum ++;    //弧的條數加一
42         }
43         else if(G->kind == UNDIGRAPH)    //如果是無向圖
44         {
45             pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode));    //建立一個弧結點
46             pArchNode->info = weight;
47             pArchNode->nextarc = NULL;
48             pArchNode->vertexIndex = endVertexIndex;
49             cur = G->vertexs[startVertexIndex]->firstarc;
50             if(NULL == cur)
51             {
52                 G->vertexs[startVertexIndex]->firstarc = pArchNode;
53             }
54             else
55             {
56                 while(cur->nextarc)
57                 {
58                     cur = cur->nextarc;
59                 }
60                 cur->nextarc = pArchNode;
61             }
62             pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode));    //再建立一個弧結點
63             pArchNode->info = weight;
64             pArchNode->nextarc = NULL;
65             pArchNode->vertexIndex = startVertexIndex;
66             cur = G->vertexs[endVertexIndex]->firstarc;
67             if(NULL == cur)
68             {
69                 G->vertexs[endVertexIndex]->firstarc = pArchNode;
70             }
71             else
72             {
73                 while(cur->nextarc)
74                 {
75                     cur = cur->nextarc;
76                 }
77                 cur->nextarc = pArchNode;
78             }
79             G->arcNum ++;    //弧的條數加一
80         }
81     }
82     else
83     {
84         cout << "起點或終點不存在!" << endl;
85         return ;
86     }
87 }

//從圖中刪除一條弧

 1 //初始條件:G存在,指定要刪除弧連線的兩個頂點
 2 void delArchFromGraph(Graph *&G,VertexType startData,VertexType endData)
 3 {
 4     ArchNode *cur,*pre;
 5     //先要找到start和end
 6     if(NULL == G)
 7         return;
 8     int startVertexIndex = findVertexIndexInGraph(G,startData);
 9     int endVertexIndex = findVertexIndexInGraph(G,endData);
10     if(startVertexIndex >= 0 && endVertexIndex >= 0)
11     {
12         if(G->kind == DIGRAPH)
13         {
14             cur = G->vertexs[startVertexIndex]->firstarc,pre = NULL;
15             while(cur)
16             {
17                 if(cur->vertexIndex == endVertexIndex)
18                 {
19                     break;
20                 }
21                 pre = cur;
22                 cur = cur->nextarc;
23             }
24             if(NULL == cur)
25             {
26                 cout << "這兩個結點之間沒有弧!" << endl;
27                 return ;
28             }
29             else
30             {
31                 if(NULL == pre)    //是首節點
32                     G->vertexs[startVertexIndex]->firstarc = cur->nextarc;
33                 else
34                     pre->nextarc = cur->nextarc;
35                 free(cur);
36                 G->arcNum --;
37             }
38         }
39         else if(G->kind == UNDIGRAPH)
40         {
41             cur = G->vertexs[startVertexIndex]->firstarc,pre = NULL;
42             while(cur)
43             {
44                 if(cur->vertexIndex == endVertexIndex)
45                 {
46                     break;
47                 }
48                 pre = cur;
49                 cur = cur->nextarc;
50             }
51             if(NULL == cur)
52             {
53                 cout << "這兩個結點之間沒有弧!" << endl;
54                 return ;
55             }
56             else
57             {
58                 if(NULL == pre)    //是首節點
59                     G->vertexs[startVertexIndex]->firstarc = cur->nextarc;
60                 else
61                     pre->nextarc = cur->nextarc;
62                 free(cur);
63                 //G->arcNum --;
64             }
65 
66             cur = G->vertexs[endVertexIndex]->firstarc,pre = NULL;
67             while(cur)
68             {
69                 if(cur->vertexIndex == startVertexIndex)
70                 {
71                     break;
72                 }
73                 pre = cur;
74                 cur = cur->nextarc;
75             }
76             if(NULL == cur)
77             {
78                 cout << "這兩個結點之間沒有弧!" << endl;
79                 return ;
80             }
81             else
82             {
83                 if(NULL == pre)    //是首節點
84                     G->vertexs[endVertexIndex]->firstarc = cur->nextarc;
85                 else
86                     pre->nextarc = cur->nextarc;
87                 free(cur);
88                 G->arcNum --;
89             }
90         }
91     }
92     else
93     {
94         cout << "起點或終點不存在!" << endl;
95         return ;
96     }
97 }

//深度優先遍歷

 1 //初始條件:圖G存在
 2 void DFSdetails(const Graph *G,int i,int satusArr[])
 3 {
 4     ArchNode *cur;
 5     if(satusArr[i] == 1 )
 6         return;
 7     cout << G->vertexs[i]->data << " ";
 8     satusArr[i] = 1;
 9     cur = G->vertexs[i]->firstarc;
10     while(cur)
11     {
12         DFSdetails(G,cur->vertexIndex,satusArr);
13         cur = cur->nextarc;
14     }
15 }
16 
17 void DFS(const Graph *G)
18 {
19     int satusArr[MAX_VERTEX_NUM] = {0};
20     cout << "深度優先遍歷:";
21     if(NULL == G)
22         return;
23     for(int i = 0; i < G->vexNum; ++i)
24     {
25         DFSdetails(G,i,satusArr);
26     }
27     cout << endl;
28 }