zoukankan      html  css  js  c++  java
  • 日日算法:Kruskal算法

    介绍

    克鲁斯卡尔(Kruskal)算法是用来求出连通图中最小生成树的算法。

    连通图:指无向图任意两点都能相通的图。
    最小生成树:指联通图的所有生成树中边权重的总和最小的树(即,找出一个树,让其联通所有的点,并让树的边权和为最小)。

    算法思想

    克鲁斯卡尔算法的主要基本思想有两点原则:

    • 按照从小到大的顺序选择边,并将边的两端连线,构成新的图
    • 保证新加入的边不能在新的图上形成环
    • 重复以上步骤,直至添加n-1条边
      用图表示该算法的解体过程:

    算法证明

    我是通过反证的方式理解该算法的。

    1. 证明按上述算法添加n-1条边时,一定能连通n个节点。

    证明:Kruskal算法保证了针对n个节点,它添加了n-1条边,且不存在环。那么假设这n-1条边没有全部连通n个节点。也就说至少有1个点没有边,那么至多只有n-1个点使用n-1条边,当n-1个点使用n-1条边时,必定构成环。与要求不符,故反正成立。

    1. 证明新的图中再添加一条边,一定构成环。

    步骤一证明了新生成的图一定是一个连通图,也就是任意两点之间必定已经相连,当我们在加入一条新的边的时候,边两段的点又多了一条新相连的路,因此构成了环。

    1. 证明在构成新的环中,新加入的边一定是最长的边。

    假设新加入的边,并非是环中最大的边,那么可以去掉这个环中最大的边,且剩下的边不够环,这与逐步加入小的边且不构成环这一条件矛盾。因此证明新加入的边一定为最长的边。

    算法实现

    public class Kruskal {
    
        public static void generateMinTree(int[][] graph){
            if(graph == null || graph.length <=0)
                throw new IllegalArgumentException();
    
            int minSum = 0;
            //标记哪些点已经到访过
            int[][] visited = new int[graph.length][graph.length];
    
            //用来表示父子级的关系,验证是否存在环
            int[] nodeHierarchy = new int[graph.length];
            for(int i=0; i<nodeHierarchy.length; i++){
                nodeHierarchy[i] = i;
            }
    
            int n = 0;
            while(n < graph.length -1){
                int minVal = Integer.MAX_VALUE;
                int iIndex = 0;
                int jIndex = 0;
    
                for(int i=0; i<graph.length; i++){
                    for(int j=i+1; j<graph[i].length; j++){
                        if(graph[i][j] != Integer.MAX_VALUE && visited[i][j] == 0 && graph[i][j] < minVal){
                            iIndex = i;
                            jIndex = j;
                            minVal = graph[i][j];
                        }
                    }
                }
                visited[iIndex][jIndex] = 1;
    
                //判断父节点是否相同,确定是否构成了环
                if(findFather(nodeHierarchy, iIndex) != findFather(nodeHierarchy, jIndex)){
                    System.out.println(n + " Round min value path: " + minVal + " from " + iIndex + " to " + jIndex);
                    minSum += graph[iIndex][jIndex];
                    updateHierarchy(nodeHierarchy, iIndex, jIndex);
                    n++;
                }
                System.out.println("node hierarchy:" + Arrays.toString(nodeHierarchy));
    
    
            }
    
            System.out.println("min tree path sum:" + minSum);
            System.out.println("node hierarchy:" + Arrays.toString(nodeHierarchy));
    
    
        }
    
        //递归查找父节点
        private static int findFather(int[] nodeHierarchy, int idx){
    
            if(nodeHierarchy[idx] == idx)
                return idx;
    
            return findFather(nodeHierarchy, nodeHierarchy[idx]);
    
        }
    
        //递归更新父节点
        private static void updateHierarchy(int[] nodeHierarchy, int from, int to){
            if(nodeHierarchy[from] != from)
                updateHierarchy(nodeHierarchy, nodeHierarchy[from], from);
            nodeHierarchy[from] = to;
        }
    
    }
    

    上述代码见Github

  • 相关阅读:
    hadoop中namenode发生故障的处理方法
    开启虚拟机所报的错误:VMware Workstation cannot connect to the virtual machine. Make sure you have rights to run the program, access all directories the program uses, and access all directories for temporary fil
    Hbase的安装与部署(集群版)
    分别用反射、编程接口的方式创建DataFrame
    用Mapreduce求共同好友
    SparkSteaming中直连与receiver两种方式的区别
    privot函数使用
    Ajax无刷新显示
    使用ScriptManager服务器控件前后台数据交互
    数据库知识
  • 原文地址:https://www.cnblogs.com/insaneXs/p/11844443.html
Copyright © 2011-2022 走看看