克鲁斯卡尔算法

克鲁斯卡尔算法也是用来寻找一个图的最小生成树的算法,与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*/
}

例题及运行结果:
在这里插入图片描述
克鲁斯卡尔算法原则上要求会手工操作,但是会写代码更棒喔!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值