克鲁斯卡尔算法生成最小生成树

20 篇文章 0 订阅
17 篇文章 1 订阅
  • 举个最小生成树的例子:
    在一个地区有很多个小村庄,并且每个村之间都可以修路进行连通。实际上,每条路由于地形不一样,所需的经费不同,并且不可能每两个村庄都直接互通,可以间接互通,从而降低经费。如何实现呢?这时候最小生成树的作用就体现出来了。
  • 如下图:(每个点代表一个村庄,边上的值代表修路所需经费)
    在这里插入图片描述
    生成最小生成树的方法最经典的有两种:普利姆算法克鲁斯卡尔算法 。下面我们来说说克鲁斯卡尔算法算法,克鲁斯卡尔算法又叫加边法。
  • 通过克鲁斯卡尔算法最小生成树的要点主要简单归纳为如下两点点:
    1)找到最短的边
    2)判断这两个边上的点能不能连接
    a.两个点是新的
    b.两个点其中一个是新的
    c.连量两个点出自不同的通区域
以C为起点为例:

1)找到最短的边
在这里插入图片描述
2)判断是否可以连通: 两个点出自不同的通区域
在这里插入图片描述
3)重复第二步
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最后将所有点都(直接或者间接)连通成功
在这里插入图片描述

上面就是克鲁斯卡尔算法的基本思路。如何用代码实现呢,往下看。

  • 代码实现

    要记录一个图,我们在代码中就要记录点还有点之间的边,所有我们需要一个点集和一个边集
    点集我们可以通过一个Set集合来充当
    边集合我们可以通过一个二维数组来建立: 如下图,表示点与点之间的距离,数组的索引对应MapNode中的index值。
    在这里插入图片描述
  • 封装一个图中所需的点
	public class MapNode {
	    public String val;
	    public List<MapNode> neighbor;//用来记录最终点周围的连接情况
	    public int index;//用于绑定图中的边集
	
	    public MapNode(String val, int index) {
	        this.val = val;
	        this.index = index;
	        neighbor = new ArrayList<>();
	    }
	}
  • 克鲁斯卡尔算法的核心代码
//克鲁斯卡尔算法
	public static void kruskal(Set<MapNode> pointSet, int[][] distance){
	        List<List<MapNode>> rs = new ArrayList<>();//部落的集合
	        while (!(rs.size() == 1 && rs.get(0).size() == pointSet.size())){
	            getMinDis(pointSet,distance,rs);
	        }
	    }
    
  //找到最短的边并且将两点按条件连接起来
     public static void getMinDis(Set<MapNode> pointSet, int[][] distance,List<List<MapNode>> rs){
        int minDis = Integer.MAX_VALUE;
        MapNode begin = null;
        MapNode end = null;
        List<MapNode> beginList = null;
        List<MapNode> endList = null;
        for(int i = 0; i < distance.length; i++){
            for(int j = 0; j < distance[i].length; j++){
                if(distance[i][j] < minDis && i != j){
                    MapNode a = getMapNodeByInx(pointSet,i);
                    MapNode b = getMapNodeByInx(pointSet,j);
                    List<MapNode> aList = getMapNodeList(rs,a);
                    List<MapNode> bList = getMapNodeList(rs,b);
                    if(!(aList != null && bList != null && aList == bList)){
                        minDis = distance[i][j];
                        begin  = a;
                        end = b;
                        beginList = aList;
                        endList = bList;
                    }
                }
            }
        }
        //循环完后便可找到最短的那天边
        begin.neighbor.add(end);
        end.neighbor.add(begin);
        if(beginList == null && endList == null){//两个都是新的点
            List<MapNode> mapNodes = new ArrayList<>();
            mapNodes.add(begin);
            mapNodes.add(end);
            rs.add(mapNodes);
        }else if(beginList != null && endList == null){
            beginList.add(end);
        }else if(beginList == null && endList != null){
            endList.add(begin);
        }else if(beginList != null && endList != null){
            beginList.addAll(endList);
            rs.remove(endList);
        }
    }
    
	//根据索引找到相应的点
	public static MapNode getMapNodeByInx(Set<MapNode> pointSet, int index){
       		 for(MapNode node : pointSet)if (node.index == index) return node;
        	 return null;
    }
	//找到点所在连通区域
	public static List<MapNode> getMapNodeList(List<List<MapNode>> rs, MapNode node){
	        for(List<MapNode> mapNodes : rs)if(mapNodes.contains(node)) return mapNodes;
	        return null;
	  }
  • 记录上面所举例的图并且通过克鲁斯卡尔算法最终生成最小生成树
public class Main {
    public static void main(String[] args) {
        //将图中的点构建出来
        MapNode pointA = new MapNode("A",0);
        MapNode pointB = new MapNode("B",1);
        MapNode pointC = new MapNode("C",2);
        MapNode pointD = new MapNode("D",3);
        MapNode pointE = new MapNode("E",4);
        MapNode pointF = new MapNode("F",5);
        MapNode pointG = new MapNode("G",6);

        int max = Integer.MAX_VALUE;
        //图中每个点到图中点的距离(每条边的权值)
        int[][] distance = new int[][]{
                {0,5,max,13,max,max,8},
                {5,0,6,max,max,max,10},
                {max,6,0,max,max,8,4},
                {13,max,max,0,9,max,11},
                {max,max,max,9,0,9,7},
                {max,max,8,max,9,0,20},
                {8,10,4,11,7,20,0}
        };

        Set<MapNode> pointSet = new HashSet<>();
        pointSet.add(pointA);
        pointSet.add(pointB);
        pointSet.add(pointC);
        pointSet.add(pointD);
        pointSet.add(pointE);
        pointSet.add(pointF);
        pointSet.add(pointG);

        kruskal(pointSet,distance);
        System.out.println("生成完毕");//debug查看结果
    }

  • 生成结果:
    在这里插入图片描述
    暂且不全部展开,可以看到,和我们上面生成的最小生成树结果是一样的。
  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值