數據結構之圖(圖的基本操作)


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

 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 }

 


免責聲明!

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



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