最小生成树 Kruskal算法 Java实现

Kruskal算法实现最小生成树

其实算法理解起来比较简单:
1 取出所有的边,对边进行排序(升序)
2 判断边是否合格
2-1判断边上的两个点是否来自于同一个集合(需要用到并查集)
3 将合格的边加到最小生成树边的集合中
4 输出这个集合

并查集的实现

并查集其实就两个功能:
1 find:找某个点的父结点
2 union:合并两个点为一个集合(使其中一个点成为另一个点的父结点)

import java.util.HashSet;
import java.util.Set;

public class UnionFind {

	public static UFNode find(UFNode x)
	{
		UFNode p=x;
		Set<UFNode> path=new HashSet<>();
		//记录向上追溯的路径上的点
		while(p.parent!=null) {
			path.add(p);
			p=p.parent;
		}
		//这些点的parent全部指向这个集的代表(他们共同的老大)
		for(UFNode ppp:path)
		{
			ppp.parent=p;
		}
		return p;
		
		/*
		 * 问题:
		 * 如果每次查找都要从"叶子"一直找到"根",很费时
		 * 解决:
		 * 因为这个集合的形态对结果并无影响
		 * 所以只要做查找的时候,把找的结点都存在一个集合中
		 * 然后将他们的父结点统一设置为共同的老大
		 * 形象点说就是将一条长链掰圆
		 * 
		 * 这样做就省去了很多查询时间
		 * */
	}
	
	public static void union(UFNode x,UFNode y)
	{
		find(y).parent=find(x);
		//将x作为y的父结点
	}
	
	//定义静态内部类,这是并查集中的结点
	public static class UFNode{
		UFNode parent;//父结点
	}
}


Kruskal实现代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Kruskal {
	private final List<Edge> edgeList;//存放图中的所有边
	private final int n;//总顶点数
	
	private Set<Edge> T =new HashSet<>();//存放生成树的边
	private Map pntAndNode=new HashMap();//边上的每个顶点都和并查集中有与之对应的node
	private Set<Edge> getT(){
		buildMST();
		return T;
	}
	
	public Kruskal(List<Edge> edgeList,int n)
	{
		this.edgeList=edgeList;
		//为每个顶点建立一个并查集的点
		for(Edge edge:edgeList)
		{
			pntAndNode.put(edge.getStart(), new UnionFind.UFNode());
			pntAndNode.put(edge.getEnd(), new UnionFind.UFNode());
		}
		this.n=n;
	}
	
	//构造一个边表
	private static List<Edge> build()
	{
		List<Edge> li=new ArrayList<>();
		li.add(new Edge("C","D",1));
		li.add(new Edge("C","A",1));
		li.add(new Edge("C","E",8));
		li.add(new Edge("A","B",3));
		li.add(new Edge("D","E",3));
		li.add(new Edge("B","C",5));
		li.add(new Edge("B","E",6));
		li.add(new Edge("B","D",7));
		li.add(new Edge("A","D",2));
		li.add(new Edge("A","E",9));
		
		return li;
	}
	
	//最小生成树的核心代码
	private void buildMST() {
		//先对边集进行排序
		Collections.sort(edgeList);
		for(Edge e:edgeList)
		{
			//寻找每条边上两个结点在map集合中映射的UFNode
			UnionFind.UFNode x=(UnionFind.UFNode) pntAndNode.get(e.getStart());
			UnionFind.UFNode y=(UnionFind.UFNode) pntAndNode.get(e.getEnd());
			if(UnionFind.find(x)==UnionFind.find(y))
				continue;//如果两个结点来自同一顶点集,则跳过这条边,否则会形成回路
			UnionFind.union(x, y);
			//把边加入到T中
			T.add(e);
			if(T.size()==n-1)
				return;//生成树的边数==总顶点数-1,表示所有的点已经连接		
		}
		/*
		 * 整体思路
		 * 对边进行排序
		 * 判断边是否合格
		 *     判断边上的两个点是否来自于同一顶点集
		 * 合格就加到生成树的边集中
		 * 
		 * */
	}
	
	public static void main(String[] args) {
		List<Edge> edgeList=build();
		Kruskal obj=new Kruskal(edgeList,5);
		for(Edge e:obj.getT())
			System.out.println(e);
		//getT中就调用了buildMST方法,将生成的边放到了集合中
	}
	
	

}

Kruskal代码涉及到的Edge类代码


public class Edge<T> implements Comparable<Edge> {

	private T start;
	private  T end;
	private int distance;
	
	/**
	 * @param start
	 * @param end
	 * @param distance
	 */
	public Edge(T start, T end, int distance) {
		this.start = start;
		this.end = end;
		this.distance = distance;
	}

	


	public T getStart() {
		return start;
	}




	public void setStart(T start) {
		this.start = start;
	}




	public T getEnd() {
		return end;
	}




	public void setEnd(T end) {
		this.end = end;
	}




	public int getDistance() {
		return distance;
	}




	public void setDistance(int distance) {
		this.distance = distance;
	}




	@Override
	public String toString() {
		return start+"->"+end+":"+distance;
	}


	@Override
	public int compareTo(Edge obj) {
		int targetDis=obj.getDistance();
		return distance>targetDis?1:(distance==targetDis?0:-1);
	}

	
}

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值