克鲁斯卡尔算法也是用来寻找一个图的最小生成树的算法,与Prim算法相同的是,二者都采用由小及大的策略,逐步将整个图的最小生成树求出,但二者不同的地方在于Prim算法逐步归并顶点,而克鲁斯卡尔算法则是逐步归并边。
算法思想:
设联通网络N = {V,E}
(1)构造一个只有n个顶点,没有边的非连通图T= {V,*},每个顶点独自成一个连通分量;
(2)在E中选最小权值的边,若该边的两个顶点落在不同的联通的分量上,则加入T中;否则舍去,重新选择;
(3)重复下去,直到所有的顶点在通一个连通分量上为止。
我们还是用图来解释一下这些苍白的语言描述吧:
话不多说我们上代码:
1.数据结构实现及相关的小函数:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define N 100
#define INITFITE 32767
using namespace std;
typedef struct Node{
int vernum,arcnum;
char a[N];
int martrix[N][N];
}Graph;
struct NNode{ //额外建立一个数据结构用来存边的信息!!
int length;
int v1;
int v2;
}Edge[N];
int cmp(const void *a,const void *b) //cmp函数,用于qsort排序函数;
{
//return ((NNode *)a)->length - ((NNode *)b)->length;或
return (*(NNode *)a).length - (*(NNode *)b).length;
}
int locate(Graph G,char ch)
{
int i;
for (i = 0;i < G.vernum;i++)
if (G.a[i] == ch)
return i;
}
2.建图:
void create_Graph(Graph &G)
{
char v1,v2;
int weight;
cout<<"please key in the vernum & arcnum"<<endl;
cin>>G.vernum>>G.arcnum;
cout<<"please key in all the vertexs"<<endl;
for (int i = 0;i < G.vernum;i++)
cin>>G.a[i];
for (int i = 0;i < G.vernum;i++)
for (int j = 0;j < G.vernum;j++)
G.martrix[i][j] = INITFITE;
cout<<"please key in the v1 & v2 & weight"<<endl;
for (int i1 = 0;i1 < G.arcnum;i1++)
{
cin>>v1>>v2>>weight;
int i = locate(G,v1);
int j = locate(G,v2);
G.martrix[i][j] = weight;
G.martrix[j][i] = weight;
/*-----------------*/
Edge[i1].length = weight;
Edge[i1].v1 = i;
Edge[i1].v2 = j;
}
}
3.克鲁斯卡尔算法:
void Clus(Graph G)
{
int VertexSet[N];
qsort(Edge,G.arcnum,sizeof(Edge[0]),cmp);//将所有的边从小到大排序
for (int i = 0;i < G.vernum;i++)**//初始化时是没有边相连的,即有G.vernum个连通分支;**
{
VertexSet[i] = i;
}
int k = 0;
for (int i = 0;i < G.arcnum;i++)
{
int h = locate(G,G.a[Edge[i].v1]);//查找该边的第一个端点的下标
int t = locate(G,G.a[Edge[i].v2]);//查找改变的第二个端点的下标
int h1 = VertexSet[h]; //查找第一个端点所在的连通分支
int t1 = VertexSet[t]; //查找第二个端点所在的连通分支
if (h1 != t1 && k < G.vernum - 1)
{
cout<<Edge[i].length<<endl;
cout<<G.a[Edge[i].v1]<<" "<<G.a[Edge[i].v2]<<endl;
k ++;
for (int j = 0;j < G.vernum;j++) //**将所有已经相连的点的连通分支统一!!!**
{
if (VertexSet[j] == t1)
VertexSet[j] = h1;
}
}
}
}
4.主函数:
int main(){
Graph G;
create_Graph(G);
for (int i = 0;i < G.vernum;i++)
{
for (int j = 0;j < G.vernum;j++)
printf ("%5d ",G.martrix[i][j]);
cout<<endl;
}
Clus(G);
return 0;
/*A B 6
A C 3
B D 1
B E 3
C D 2
C E 9
D E 7*/
/*A B 6
A C 1
A D 5
B C 5
B E 3
C E 6
C F 4
C D 5
D F 2
E F 6*/
}
例题及运行结果:
克鲁斯卡尔算法原则上要求会手工操作,但是会写代码更棒喔!!!