最小生成树之Kruskals算法的实现

最小生成树之Kruskals算法的实现

  1. 首先要实现图的封装
package _7图;

/**
 * 边的封装
 * 边集可以用来表示图
 */
public class Edge<T>implements Comparable<Edge> {
   private T start ; //重要的就是三个属性
   private T end;
   private int distance;
	public Edge(T start, T end, int distance) {//有参的构造方法
		this.start = start;
		this.end = end;
		this.distance = distance;//距离
	}

	@Override
	public int compareTo(Edge obj) {
		// TODO Auto-generated method stub
		int targetDis = obj.getDistance();
	    return distance > targetDis ? 1 : (distance == targetDis ? 0 : -1);
	}
  //下面getter he set方法
	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;
	}


}

  1. Kruskals算法实现 细节过程如下
package _7图;

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;

/*
 * Kruskal实现
 */
public class _5Kruskal {
   private final List<Edge> edgeList;  //边集 > 边的权值
   private final int n;  //总顶点数
   
   private Set<Edge>T =new HashSet<>();  //生成树的边集   >  一开始是空的

   private Map pntAndNode=new HashMap(); //映射 >使顶点和节点建立纽带
   //6、第五步
   public Set<Edge>getT(){
	    buildMST();
	    return T; //返回生成树
   }
   //7、构造MST的核心方法
private void buildMST() {
   Collections.sort(edgeList); //对边值进行排序,升序	
   for(Edge e:edgeList) { //迭代没条边的权值
	       if(!ok(e)) { //如果不可以合并加入,则跳过。
	    	   continue; 
	       }
	       //确认过了,那么就把边都加入进来
	       T.add(e);
	       //12、判断最小生产树是否生成了
	       if(T.size()==n-1) {
	    	   return ;  //生成的边数==总顶点-1 => 所有点都已经连接
	       }
   }
	
}
      //8、并查集中查询e的起点和终点是否在一个集合(并查集的核心)
      private boolean ok(Edge e) {
	//开始把节点拿出来
	     UnionFind.UFNode x=(UnionFind.UFNode)pntAndNode.get(e.getStart()); //Oject类形的,需要转化
	     UnionFind.UFNode y=(UnionFind.UFNode)pntAndNode.get(e.getEnd());
	     if(UnionFind.find(x)!=UnionFind.find(y)) { //如果两个节点不在同一个结合
		        UnionFind.union(x, y); //进行和并
		        return true;   
	}
	
	return false;
}
     //4、构造器,传入一个边集和顶点数 (完成初始化)
public _5Kruskal(List<Edge> edgeList, int n) { 
	this.edgeList = edgeList;
	//为每个顶点建立一个并查集的点
	for(Edge edge:edgeList) {
		//映射关系,把各个顶点与节点建立纽带添加到pntAndNode中
		pntAndNode.put(edge.getStart(), new UnionFind.UFNode()); //由此setStrart不是一个简单的字符
		pntAndNode.put(edge.getEnd(),new UnionFind.UFNode());
	}
	this.n = n;
}
   public static void main(String[] args) {
	   //总体走的路线:12个步骤
//	   List > obj   >gotT()   > buildMST()   >....
		// 1、构造边集合
		List<Edge>edgeList=build();
	    //3、传入边集和顶点返回生成树
	   _5Kruskal obj=new _5Kruskal(edgeList, 5);
	    //5、obj对象调用方法getT()方法
	    int distance=0; // 总的权值
        for(Edge e:obj.getT()) {
    	System.out.println(e.getDistance());//权值就是1 1 3 3构成最小生产树
    	distance+=e.getDistance();
    }
    System.out.println("总的权值是:"+distance);
}      //2、完成构造边集
    private static List<Edge> build(){
    	List<Edge>l=new ArrayList(); //用一个链表存储
    	l.add(new Edge("C","D", 1));
    	l.add(new Edge("C","A",1));
    	l.add(new Edge("C","E",8));
    	l.add(new Edge("A","B",3));
    	l.add(new Edge("D","E",3));
    	l.add(new Edge("B","E",5));
    	
    	l.add(new Edge("B","E",6));
    	l.add(new Edge("B","D",7));
    	l.add(new Edge("A","D",2));
    	l.add(new Edge("A","E",9));
    	
		return l;
    	
    }
}
//下面进行创建一个UnionFind并查集工具类

class UnionFind{
	//9、对两个节点进行判断是否在同一个集合
	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 pp:path) {
			pp.parent=p;
		}
		return p; //反回根root
	}
	//10、对两个节点进行合并
	public static void union(UFNode x,UFNode y) { // 把y 并到x中
		find(y).parent=find(x); 
	}
	public static class UFNode{ //单指针,父节点
		UFNode parent;
	}
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金石不渝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值