无向网的最小生成树——Kruskal算法(转)

最小生成树的Kruskal算法,适用于边较少的连通网,下面的算法中没有将其像上一篇日志一样转换为一棵树,要转换的话就像上一篇日志一样,进行建树就可以了,下面是代码

"graph.h"文件

  1 #include<iostream>
2 #include<queue>
3 #include<string>
4 using namespace std;
5
6 const int MAX_VERTEX_NUM=20;
7 bool visited[20];//用于遍历时辅组使用
8
9 class VNode;
10 //表结点
11 class ArcNode
12 {
13 public:
14 int adjvex;
15 int weight;
16 ArcNode *nextarc;
17 friend class VNode;
18 };
19
20 class ALGraph;
21 //头结点
22 class VNode
23 {
24 string data;
25 ArcNode *firstarc;
26 friend class ALGraph;
27 };
28
29 class EDGE
30 {
31 public:
32 int begin;
33 int end;
34 int cost;
35 friend class ALGraph;
36 };
37
38 EDGE edges[20]; //设为全局变量,便于将初始化和使用分开
39
40 class ALGraph
41 {
42 private:
43 VNode vertices[MAX_VERTEX_NUM];
44 int vexnum;
45 int arcnum;
46 public:
47 void CreateUDG_ALG()
48 {
49 //采用邻接表构造无向网G
50 //创建邻接表的过程顺便将信息存入edges中,便于后面的求最小生成树
51 string v1,v2;
52 int i,j,k,w;
53 cout<<"输入顶点数和边数:";
54 cin>>vexnum>>arcnum;
55
56 cout<<"输入顶点民称:";
57 for(i=0;i<vexnum;i++)
58 {
59 cin>>vertices[i].data;
60 vertices[i].firstarc=NULL;
61 }
62
63 //输入各弧并构造邻接表
64 for(k=0;k<arcnum;k++)
65 {
66 cout<<"输入边所对应的两个顶点和该边的权值:";
67 cin>>v1>>v2>>w;
68 i=Locate_Vex(v1);
69 j=Locate_Vex(v2);
70 while(i<0|| i>vexnum-1 || j<0 || j>vexnum-1)
71 {
72 cout<<"结点位置输入错误,重新输入: ";
73 cin>>v1>>v2>>w;
74 i=Locate_Vex(v1);
75 j=Locate_Vex(v2);
76 }
77
78 ArcNode *p=new ArcNode;
79 p->adjvex=j;
80 p->weight=w;
81 p->nextarc=vertices[i].firstarc;
82 vertices[i].firstarc=p;
83
84 ArcNode *q=new ArcNode;
85 q->adjvex=i;
86 q->weight=w;
87 q->nextarc=vertices[j].firstarc;
88 vertices[j].firstarc=q;
89
90 edges[k].begin=i;
91 edges[k].end=j;
92 edges[k].cost=w;
93 }
94 }
95
96 int Locate_Vex(string v) //返回顶点在数组中的位置
97 {
98 for(int k=0;vertices[k].data!=v;k++);
99 return k;
100 }
101
102 void BFS_Traverse() //广度优先遍历
103 {
104 int i,k,w;
105 queue<int> q;
106 ArcNode *p;
107 for(i=0;i<vexnum;i++)
108 visited[i]=false;
109 for(i=0;i<vexnum;i++)
110 {
111 if(!visited[i])
112 {
113 visited[i]=true;
114 cout<<vertices[i].data<<" ";
115 if(vertices[i].firstarc)
116 q.push(i);
117 while(!q.empty())
118 {
119 k=q.front();
120 q.pop();
121 for(p=vertices[k].firstarc;p;p=p->nextarc)
122 {
123 w=p->adjvex;
124 if(!visited[w])
125 {
126 visited[w]=true;
127 cout<<vertices[w].data<<" ";
128 if(vertices[w].firstarc)
129 q.push(w);
130 }
131 }
132 }
133 }
134 }
135 }
136
137 //深度优先遍历
138 void DFS_Traverse()
139 {
140 for(int i=0;i<vexnum;i++)
141 visited[i]=false;
142 for(i=0;i<vexnum;i++)
143 if(!visited[i])
144 DFS(i);
145 }
146
147 void DFS(int i)
148 {
149 visited[i]=true;
150 cout<<vertices[i].data<<" ";
151 ArcNode *p;
152 for(p=vertices[i].firstarc;p;p=p->nextarc)
153 {
154 int w=p->adjvex;
155 if(!visited[w])
156 DFS(w);
157 }
158 }
159
160 /*Kruskal算法*/
161 /*------------------------------------------------
162 /假设N=(V,{VR})是一个连通网,令最小生成树初始状态为
163 /只有n个顶点的非连通图,T=(V,{}),图中的每个顶点自成
164 /一个连通分量.在VR中选择权值最小边,若该边依附的顶点
165 /落在T的不同连通分量上,则将此边加入T中,然后合并连个
166 /连通分量否则就舍弃那条边,直至T中所有顶点都在同
167 /一连通分量上为止。
168 /--------------------------------------------------
169 /为了判断所选的边加入到生成树中是否会形成回路,可以
170 /将各个顶点划分为所属集合的方法来解决,每个集合中的顶点
171 /表示一个无回路的连通分量.用parents[]表示这些顶点,初始
172 /值为0,表示各顶点自成一个连通分量.从edges中依次序选择
173 /一条边时,查找它的两个顶点所属的分量的bnf和edf.
174 /当bnf和edf不同时,就说明该边的两个顶点属于两个不同
175 /集合,相等时说明在同一个集合。
176 /------------------------------------------------*/
177 void Kruskal_Min_Tree()
178 {
179 int bnf,edf;
180 int parents[20];
181 Sort(edges); //按照权值大小排序
182
183 for(int i=0;i<vexnum;i++) //初始化parent[]数组
184 parents[i]=0;
185 for(i=0;i<arcnum;i++)
186 {
187 bnf=Find(parents,edges[i].begin);
188 edf=Find(parents,edges[i].end);
189 if(bnf!=edf)
190 {
191 parents[bnf]=edf;
192 cout<<"("<<vertices[edges[i].begin].data<<','<<vertices[edges[i].end].data<<','<<edges[i].cost<<')'<<endl;
193 }
194 }
195 }
196
197 void Sort(EDGE edges[])
198 {
199 for(int i=0;i<arcnum;i++)
200 for(int j=i+1;j<arcnum;j++)
201 if(edges[i].cost>edges[j].cost)
202 {
203 EDGE temp;
204 temp.begin=edges[i].begin;
205 temp.end=edges[i].end;
206 temp.cost=edges[i].cost;
207 edges[i].begin=edges[j].begin;
208 edges[i].end=edges[j].end;
209 edges[i].cost=edges[j].cost;
210 edges[j].begin=temp.begin;
211 edges[j].end=temp.end;
212 edges[j].cost=temp.cost;
213 }
214 }
215
216 int Find(int parents[],int f)
217 {
218 while(parents[f]>0)
219 f=parents[f];
220 return f;
221 }
222
223 };

  测试函数"main.cpp"

 1 #include"graph.h"
2
3 int main()
4 {
5 ALGraph G;
6 G.CreateUDG_ALG();
7
8 cout<<"图的广度优先遍历为:";
9 G.BFS_Traverse();
10 cout<<endl;
11
12 cout<<"图的深度优先遍历为:";
13 G.DFS_Traverse();
14 cout<<endl;
15
16 cout<<"最小生成树的边的组成和对应的权值为:"<<endl;
17 G.Kruskal_Min_Tree();
18 cout<<endl;
19
20 return 0;
21 }

  输出结果:

 1 输入顶点数和边数:9 15
2 输入顶点民称:v1 v2 v3 v4 v5 v6 v7 v8 v9
3 输入边所对应的两个顶点和该边的权值:v1 v6 7
4 输入边所对应的两个顶点和该边的权值:v1 v7 3
5 输入边所对应的两个顶点和该边的权值:v1 v2 2
6 输入边所对应的两个顶点和该边的权值:v2 v7 6
7 输入边所对应的两个顶点和该边的权值:v2 v3 4
8 输入边所对应的两个顶点和该边的权值:v6 v5 6
9 输入边所对应的两个顶点和该边的权值:v6 v9 5
10 输入边所对应的两个顶点和该边的权值:v7 v9 1
11 输入边所对应的两个顶点和该边的权值:v7 v8 3
12 输入边所对应的两个顶点和该边的权值:v3 v8 2
13 输入边所对应的两个顶点和该边的权值:v3 v4 2
14 输入边所对应的两个顶点和该边的权值:v9 v5 2
15 输入边所对应的两个顶点和该边的权值:v9 v8 4
16 输入边所对应的两个顶点和该边的权值:v8 v4 8
17 输入边所对应的两个顶点和该边的权值:v5 v4 1
18 图的广度优先遍历为:v1 v2 v7 v6 v3 v8 v9 v5 v4
19 图的深度优先遍历为:v1 v2 v3 v4 v5 v9 v8 v7 v6
20 最小生成树的边的组成和对应的权值为:
21 (v7,v9,1)
22 (v5,v4,1)
23 (v3,v8,2)
24 (v3,v4,2)
25 (v9,v5,2)
26 (v1,v2,2)
27 (v1,v7,3)
28 (v6,v9,5)
29
30 Press any key to continue

  

原文地址:https://www.cnblogs.com/math2010/p/2142073.html