数据结构之图(图的基本操作)

由于图的基本操作的代码较多,我放到这一章来写。图可以用两种方法来存储,但是本人偏爱链表的表示方法,所以以下代码也都是是基于邻接链表的存储方式。

 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 }

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/zhuwbox/p/3649013.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞