最小生成树---kruskal算法

克鲁斯卡尔(Kruskal)算法(只与边相关)
 
算法描述:克鲁斯卡尔算法需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边有关系,可以证明其时间复杂度为O(eloge)。
算法过程:
1.将图各边按照权值进行排序
2.将图遍历一次,找出权值最小的边,(条件:此次找出的边不能和已加入最小生成树集合的边构成环),若符合条件,则加入最小生成树的集合中。不符合条件则继续遍历图,寻找下一个最小权值的边。
3.递归重复步骤1,直到找出n-1条边为止(设图有n个结点,则最小生成树的边数应为n-1条),算法结束。得到的就是此图的最小生成树。
 
克鲁斯卡尔(Kruskal)算法因为只与边相关,则适合求稀疏图的最小生成树。而prime算法因为只与顶点有关,所以适合求稠密图的最小生成树。
代码如下:
#include<iostream>
#include<iomanip>
using namespace std;

struct Edge				//均为无向图边集
{
	char startkey;
	char endkey;
	int weight;			//权值
};

class Kruskal
{
public:
	Kruskal(Edge* _edges,int _edgenum,char *_keyArray,int _vertexnum);
	void SortEdge();
	void MSTKruskal();									//找到最小生成树
	int FindSet(int *vertex,int childnum);				//找到包含下标为childnum元素的集合中的一个代表元素
	void MakeSet(int *vertex,int vertexnum);			//初始化各集合,初始时各元素所在集合的代表元素为自己下标
	int FindKey(char key);	//找到key对应在keyArray的位置,映射到vertex的下标
	void Union(Edge *edge);
	void OutputTree();
private:
	int kruskalnum;
	int edgenum;
	int vertexnum;
	char *keyArray;
	Edge *kruskaltree;
	Edge *edges;
};

Kruskal::Kruskal(Edge* _edges,int _edgenum,char *_keyArray,int _vertexnum)
{
	edges = new Edge[_edgenum];
	kruskaltree = new Edge[_vertexnum - 1];				//最小生成树的边数只比节点-1
	keyArray = new char[_vertexnum];
	int i;
	for(i = 0; i < _edgenum; i++)
	{
		edges[i].startkey = _edges[i].startkey;
		edges[i].endkey = _edges[i].endkey;
		edges[i].weight = _edges[i].weight;
	}

	for(i = 0; i < _vertexnum;i++)
		keyArray[i] = _keyArray[i];
	edgenum = _edgenum;
	kruskalnum = 0;
	vertexnum = _vertexnum;
	SortEdge();
}

void Kruskal::SortEdge()					//这里排序就只做简单的插入排序
{
	int i,j;
	Edge temp;
	for(i = 1;i < edgenum;i++)
	{
		temp.startkey = edges[i].startkey;
		temp.endkey = edges[i].endkey;
		temp.weight = edges[i].weight;
		for(j = i - 1;j >= 0;j--)
		{
			if(edges[j].weight > temp.weight)
			{
				edges[j + 1].startkey = edges[j].startkey;
				edges[j + 1].endkey = edges[j].endkey;
				edges[j + 1].weight = edges[j].weight;
			}
			else
				break;
		}
		edges[j + 1].startkey = temp.startkey;
		edges[j + 1].endkey = temp.endkey;
		edges[j + 1].weight = temp.weight;
	}
}

void Kruskal::MSTKruskal()
{
	int i;
	int startnum,endnum;
	int *vertex = new int[vertexnum];
	MakeSet(vertex,vertexnum);
	for(i = 0; i < edgenum;i++)
	{
		startnum = FindKey(edges[i].startkey);
		endnum = FindKey(edges[i].endkey);
		startnum = FindSet(vertex,startnum);
		endnum =FindSet(vertex,endnum);
		if(startnum != endnum)
		{
			vertex[endnum] = startnum;
			Union(&(edges[i]));
			if(kruskalnum == (vertexnum + 1))				//当最小生成树边数为节点数 - 1就可以直接退出去了
				return;
		}
	}
}

int Kruskal::FindSet(int *vertex,int childnum)
{
	while(vertex[childnum] != childnum)
	{
		childnum = vertex[childnum];
	}
	return childnum;
}

void Kruskal::MakeSet(int *vertex,int vertexnum)
{
	for(int i = 0; i < vertexnum;i++)
	{
		vertex[i] = i;
	}
}

int Kruskal::FindKey(char key)
{
	for(int i = 0; i < vertexnum;i++)
	{
		if(keyArray[i] == key)
			return i;
	}
}

void Kruskal::Union(Edge *edge)
{
	kruskaltree[kruskalnum].startkey = edge->startkey;
	kruskaltree[kruskalnum].endkey = edge->endkey;
	kruskaltree[kruskalnum].weight = edge->weight;
	kruskalnum++;
}

void Kruskal::OutputTree()
{
	cout<<"The result of Kruskal Spanning Tree is :"<<endl;
	for(int i = 0; i < kruskalnum;i++)
		cout<<setw(5)<<kruskaltree[i].startkey<<setw(5)<<kruskaltree[i].endkey<<setw(10)<<kruskaltree[i].weight<<endl;
}

int main()
{
	Edge edges[] = {{'a','b',4},{'a','h',8},{'b','h',11},{'b','c',8},{'c','i',2},{'c','d',7},{'c','f',4},{'d','e',9},{'d','f',14},{'g','f',2},{'h','g',1},{'h','i',7},{'i','g',6},{'e','f',10}};
	char vertex[] = {'a','b','c','d','e','f','g','h','i'};
	Kruskal *kruskal = new Kruskal(edges,14,vertex,9);
	kruskal->MSTKruskal();
	kruskal->OutputTree();
	return 0;
}


  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值