最小生成树的kruskal算法

来源:互联网 发布:java map中嵌套map 编辑:程序博客网 时间:2024/06/04 09:22

Kruskal算法思想

不同于Prim算法,Kruskal算法是一种按照连通网中边的权值的递增顺序构造最小生成树的算法。假设G=(V,E)是一个具有n个顶点的连通网,T=(U,TE)是G的最小生成树。

Kruskal算法的基本思想是

令集合U的初值为U=V,即包含有G中全部顶点,集合TE的初值为TE={}。然后,将图G中的边按权值从小到大的顺序依次选取,若选取的边使生成树T不形成回路,则把它并入TE中,保留作为T的一条边;若选取的边使生成树T形成回路,则将其舍弃,如此进行下去,直到TE中包含有n-1条边为止,此时的T即为最小生成树。

 

 

伪代码:                                 

Kruskal(G)

1.For all u∈V do

         makeset(u);            //初始化,让每个点成为独立的连通块

2. X={Æ};                     

3. Sort the edges E by weight;            //按边的权值大小排序

4. For all edges (u, v) ∈ E in increasingorder of weight do           //对于条边e(u,v)(权值递增顺序)判断能否加入到图中

       iffind(u) ≠find(v) then                        //如两个端点不在同一个连通块,则合并这两个连通块

          add edge (u, v) to X;

          union(u, v);

 

具体实现:

窗体顶端

最小生成树的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

 

原创粉丝点击