最小生成树——Kruskal

头文件"Graph.h"

#include<iostream>
#include<algorithm>
using namespace std;

class Edge{
public:
	int start;
	int end;
	int weight;
};
//sort() 第三个参数 从小到大排序
bool cmp(const Edge & a,const Edge & b){
	return a.weight<b.weight;
}

class Graph{
public:
	Edge *edge;
	int vertexNum,edgeNum;
	int *root,*next;
	Graph(int v,int e){
		vertexNum=v;
		edgeNum=e;
		edge=new Edge [e];
		root=new int [vertexNum];
		next=new int [vertexNum];
		for(int i=0;i<vertexNum;i++){
			root[i]=i;
			next[i]=i;
		}
	}
	~Graph(){
		delete [] edge;
		delete [] root;
		delete [] next;
	}
	void setedge(int s,int e,int w,int i){
		edge[i].start=s;
		edge[i].end=e;
		edge[i].weight=w;
	}
	//root[x]存放x的父顶点,递归求x的父顶点
	int findroot(int x){
		return root[x]==x?x:findroot(root[x]);
	}
	bool Union(int v,int u){
		int root1=findroot(v);
		int root2=findroot(u);
		if(root1==root2)//说明v,u在同一个连通分量里,退出
			return false;
		else{
			//v,u所在连通分量的父顶点合并
			if(next[root1]>next[root2]){
				root[root2]=root1;
				next[root1]+=next[root2];
			}
			else{
				root[root1]=root2;
				next[root2]+=next[root1];
			}
		}
		return true;
	}
	int Kruskal(){
		int sum=0;
		int edgenum=0;
		sort(edge,edge+edgeNum,cmp);
		for(int i=0;i<edgeNum;i++){
			if(Union(edge[i].start,edge[i].end)){
				sum+=edge[i].weight;
				cout<<"v"<<edge[i].start+1<<"->"<<"v"<<edge[i].end+1<<endl;
				edgenum++;
			}
			//生成树条件顶点数为n,边数为n-1
			if(edgenum==vertexNum-1)
				break;
		}
		return sum;
	}

};


源文件"main.cpp"

#include<iostream>
#include"Graph.h"
using namespace std;

int main(){
	Graph G(6,10);
	int result;
	G.setedge(0,1,6,0);
	G.setedge(0,2,1,1);
	G.setedge(0,3,5,2);
	G.setedge(1,2,5,3);
	G.setedge(1,4,3,4);
	G.setedge(2,3,5,5);
	G.setedge(2,4,6,6);
	G.setedge(2,5,4,7);
	G.setedge(3,5,2,8);
	G.setedge(4,5,6,9);
	result=G.Kruskal();
	cout<<result<<endl;
	return 0;
}

之前一直在纠结什么时候要写Edge类,什么时候直接用int **edge,对比Prim,个人感觉因为Prim算法利用顶点更新其余顶点的信息,故在遍历时通过对每个顶点的访问,用for(){for()}比较方便,可是Kruskal算法的优点在于时间复杂度与边数相关,如果这时还用二维数组遍历的话时间复杂度就变成O(n^2)了,所以用Edge类来保存边的信息,在访问边的同时可以提取边两端顶点就方便很多啦。

                                                                                                                                                                                                         

                                                                                                                                                                                                             以上观点,仅限个人愚见,非喜勿喷。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值