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

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

 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 }

 

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构的相关操作 C语言 #include <stdio h> #include <malloc h> #include <string h> #define MAXVEX 100 typedef char VertexType[3]; 定义VertexType为char数组类型 typedef struct vertex { int adjvex; 顶点编号 VertexType data; 顶点的信息 } VType; 顶点类型 typedef struct graph { int n e; n为实际顶点数 e为实际边数 VType vexs[MAXVEX]; 顶点集合 int edges[MAXVEX][MAXVEX]; 边的集合 } AdjMatix; 的邻接矩阵类型 typedef struct edgenode { int adjvex; 邻接点序号 int value; 边的权值 struct edgenode next; 下一条边的顶点 } ArcNode; 每个顶点建立的单链表中结点的类型 typedef struct vexnode { VertexType data; 结点信息 ArcNode firstarc; 指向第一条边结点 } VHeadNode; 单链表的头结点类型 typedef struct { int n e; n为实际顶点数 e为实际边数 VHeadNode adjlist[MAXVEX]; 单链表头结点数组 } AdjList; 的邻接表类型 int visited[MAXVEX]; void DispAdjList AdjList G { int i; int in[G >n] out[G >n]; for i 0;i<G >n;i++ {in[i] 0 out[i] 0; } ArcNode p; printf "的邻接表表示如下: n" ; for i 0;i<G >n;i++ { printf " 结点 [%d %3s] >" i G >adjlist[i] data ; p G >adjlist[i] firstarc; while p NULL { out[i]++; 对于结点的出度加1 in[p >adjvex] ++; 邻接表中的结点的序号所在的结点的入度 加1 printf " %d >" p >adjvex ; p p >next; } printf "∧ n" ; } for i 0;i<G >n;i++ { printf " 结点 [%d %3s]的度 :%d n" i G >adjlist[i] data in[i]+out[i] ; } } void MatToList AdjMatix g AdjList &G 算法:将邻接矩阵g转换成邻接表G { int i j; ArcNode p; G AdjList malloc sizeof AdjList ; for i 0;i<g n;i++ 给邻接表中所有头结点的指针域置初值 { G >adjlist[i] firstarc NULL; strcpy G >adjlist[i] data g vexs[i] data ; } for i 0;i<g n;i++ 检查邻接矩阵中每个元素 for j g n 1;j> 0;j if g edges[i][j] 0 邻接矩阵的当前元素不为0 { p ArcNode malloc sizeof ArcNode ; 创建一个结点 p p >value g edges[i][j];p >adjvex j; p >next G >adjlist[i] firstarc; 将 p链到链表后 G >adjlist[i] firstarc p; } G >n g n;G >e g e; } void DFS AdjList g int vi 对邻接表G从顶点vi开始进行深度优先遍历 { ArcNode p; printf "下标%d结点%3s >" vi g >adjlist[vi] data ; 访问vi顶点 visited[vi] 1; 置已访问标识 p g >adjlist[vi] firstarc; 找vi的第一个邻接点 while p NULL 找vi的所有邻接点 { if visited[p >adjvex] 0 DFS g p >adjvex ; 从vi未访问过的邻接点出发深度优先搜索 p p >next; 找vi的下一个邻接点 } } void DFS1 AdjList G int vi 非递归深度优先遍历算法 { ArcNode p; ArcNode St[MAXVEX]; int top 1 v; printf "%d > " vi ; 访问vi顶点 visited[vi] 1; 置已访问标识 top++; 将初始顶点vi的firstarc指针进栈 St[top] G >adjlist[vi] firstarc; while top> 1 栈不空循环 { p St[top];top ; 出栈一个顶点为当前顶点 while p NULL 循环搜索其相邻顶点 { v p >adjvex; 取相邻顶点的编号 if visited[v] 0 若该顶点未访问过 { printf "%d > " v ; 访问v顶点 visited[v] 1; 置访问标识 top++; 将该顶点的第1个相邻顶点进栈 St[top] G >adjlist[v] firstarc; break; 退出当前顶点的搜索 } p p >next; 找下一个相邻顶点 } } } void BFS AdjList G int vi 对邻接表g从顶点vi开始进行广宽优先遍历 { int i v; int Qu[MAXVEX] front 0 rear 0; 循环队列 ArcNode p; printf "%d > " vi ; 访问初始顶点 visited[vi] 1; 置已访问标识 rear rear 1 %MAXVEX; 循环移动队尾指针 Qu[rear] vi; 初始顶点进队 while front rear 队列不为空时循环 { front front+1 % MAXVEX; v Qu[front]; 顶点v出队 p G >adjlist[v] firstarc; 找v的第一个邻接点 while p NULL 找v的所有邻接点 { if visited[p >adjvex] 0 未访问过则访问之 { visited[p >adjvex] 1; 置已访问标识 printf "%d > " p >adjvex ; 访问该点并使之入队列 rear rear+1 % MAXVEX; 循环移动队尾指针 Qu[rear] p >adjvex; 顶点p >adjvex进队 } p p >next; 找v的下一个邻接点 } } } int main { int i j; AdjMatix g; AdjList G; int a[5][5] {{0 1 0 1 0} {1 0 1 0 0} {0 1 0 1 1} {1 0 1 0 1} {0 0 1 1 0}}; char vname[MAXVEX] {"a" "b" "c" "d" "e"}; g n 5;g e 6; 连通 int a[5][5] {{0 1 0 1 0} {1 0 1 0 0} {0 1 0 1 0} {1 0 1 0 0} {0 0 0 0 0}}; char vname[MAXVEX] {"a" "b" "c" "d" "e"}; g n 5;g e 4; 非连通 int a[4][4] {{0 1 1 1} {1 0 1 1} {1 1 0 1} {1 1 1 0}}; char vname[MAXVEX] {"a" "b" "c" "d"}; g n 5;g e 12; int a[5][5] {{0 1 1 1 0} {1 0 1 1 1} {1 1 0 1 0} {1 1 1 0 1} {0 1 0 1 0}}; char vname[MAXVEX] {"a" "b" "c" "d" "e"}; g n 5;g e 16; 建立的无向 每1条无向边算为2条有向边 int a[6][6] { p151 7 22的代价矩阵改成的邻接矩阵 {0 1 1 0 1 0} {0 0 1 0 1 0} {1 0 0 1 0 0} {0 1 0 0 1 0} {0 0 0 1 0 0} {0 0 0 1 0 0}}; char vname[MAXVEX] {"v0" "v1" "v2" "v3" "v4" "v5"}; g n 6;g e 11; for i 0;i<g n;i++ strcpy g vexs[i] data vname[i] ; for i 0;i<g n;i++ for j 0;j<g n;j++ g edges[i][j] a[i][j]; MatToList g G ; 生成邻接表 DispAdjList G ; 输出邻接表 for i 0;i<g n;i++ visited[i] 0; 顶点标识置初值 printf "从顶点0的深度优先遍历序列: n" ; printf " 递归算法:" ;DFS G 0 ;printf " n" ; for i 0;i<g n;i++ visited[i] 0; 顶点标识置初值 printf " 非递归算法:" ; DFS1 G 0 ; printf " n" ; printf "从顶点0的广度优先遍历序列: n" ; for i 0;i<g n;i++ visited[i] 0; 顶点标识置初值 printf " t" ;BFS G 0 ; printf " n" ; scanf "%d" ; return 0; }">数据结构的相关操作 C语言 #include <stdio h> #include <malloc h> #include <string h> #define MAXVEX 100 typedef char VertexType[3]; 定义VertexType为char数组类型 typedef struct vertex { int adjvex; 顶点编号 VertexType data; 顶 [更多]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值