克鲁斯卡尔算法(kruskal)

9 篇文章 0 订阅
6 篇文章 0 订阅
我自己感觉,克鲁斯卡尔算法比普利姆算法更好理解,它就两个要点,排序和判断是否成环。
排序:我们把两两相邻的边根据边的权值,从小到大依次排序,这个十大排序算法可以自己选一个去实现下,刚好还可以回忆下以前的算法,下面我们使用冒泡来实现边的排序。
是否成环:这个也是这个算法里比较难的一个点了,这里使用了并查集,每次添加一条边时候,我们需要去寻找这两个点是否有相同的父节点,如果有说明成环了,我们就可以选择下一条边了,直到有n-1条边。
如果不了解并查集的,可以看看下面这一篇文章,讲的很通俗易懂。 (https://zhuanlan.zhihu.com/p/93647900)
下面依然是给出关键步骤代码,基本的图数据结构可以自己动手实现哦。
//边对象
class Edata {
	private int start;
	private int end;
	private int weight;
	public Edata(int start, int end, int weight) {
		this.start = start;
		this.end = end;
		this.weight = weight;
	}
}

//还是写下图对象,也没有几行
class Graph {
	//结点数量
	private int verxs;
	//结点数组
	private char[] data;
	//矩阵图
	private int[][] weigth; 
}

//记录每个结点的父结点,初始化的时候,每个结点的父节点是它自己
private int[] rank;
//最后我们获取到的边
private Edata[] result;

public void kruskal(Graph graph) {
	//辅助索引,用来存放最后我们获取到的边;
	int index = 0;
	//获取图中所有边
	Edata[] eDatas = getEDates(graph);
	//把边按权值进行排序
	sort(edatas)
	//依次取出边
	for(int i = 0; i < eDatas.length; i++) {
		//获取结点的索引
		int m = eDatas[i].getStart();
		int n = eDatas[i].getEnd();
		//获取连个结点的父节点
		int a = getRoot(m);
		int b = getRoot(n);
		//不同就把这条边加入进去
		if(a != b) {
			//这里其实就是合并两个集合
			rank[a] = b;
			result[index++] = eDatas[i];
		}
	}
}

//获取当前结点的根节点,可以想象成一棵树,不断往上找
public int getRoot(int n) {
	while(rank[n] != n) {
		n = rank[n];
	}
	return n;
}

//冒泡排序
public void sort(Edata[] eDatas) {
	Edata[] edatas = getEDates(graph);
}

//获取边的集合
public Edata[] getEDates(Graph graph) {
	int index = 0;
	//n个结点,n-1条边
	Edata eDatas = new Edata[graph.getVerxs - 1];
	//广度遍历
	for(int i = 0; i < graph.getVerxs(); i++) {
		//把自己和前面已经生成的边排除
		for(int j = i + 1; j < graph.getVerxs(); j++) {
			edatas[index++] = new Edata(graph.getData()[i], graph.getData()[j], graph.getWeight()[i][j]);
		}
	}
	return eDatas;
}

到此克鲁斯卡尔算法算是完了,代码虽然比普利姆的多些,但是结构还是很清楚的,记住两个要点排序,是否成环就OK了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值