克鲁斯卡尔算法基础

克鲁斯卡尔算法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K9AUFSZa-1579085108337)(images/19.png)]

算法介绍

  1. 克鲁斯卡尔算法:是用来求加权连通图的最小生成树的算法
  2. 基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路
  3. 具体做法: 首先构造一个只包含n个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林,并使得森林中不产生回路,值只森林变成一颗树为止

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cWdJ5GTq-1579085108339)(images/20.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cDLSNG9O-1579085108342)(images/21.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjiABLKR-1579085108344)(images/22.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K2BkjvZP-1579085108346)(images/23.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lWSk5Hio-1579085108349)(images/24.png)]

代码实现

package L十大算法.Kruskal;

import com.sun.javafx.geom.Edge;

import java.util.Arrays;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/1/15 0015  17:16
 */
public class KruskalAlgrothim {


    private int edgeNum; //边的个数
    private char[] vertexs;//顶点数组
    private int[][] matrix;//领结矩阵
    //使用INF表示两个顶点不能连通
    private static final int INF = Integer.MAX_VALUE;

    public static void main(String[] args) {

        char[]  vertexs = {'A','B','C','D','E','F','G'};
        //克鲁斯卡尔算法的邻接矩阵
        int matrix[][] = {
                /*A*//*B*//*C*//*D*//*E*//*F*//*G*/
                /*A*/ {   0,  12, INF, INF, INF,  16,  14},
                /*B*/ {  12,   0,  10, INF, INF,   7, INF},
                /*C*/ { INF,  10,   0,   3,   5,   6, INF},
                /*D*/ { INF, INF,   3,   0,   4, INF, INF},
                /*E*/ { INF, INF,   5,   4,   0,   2,   8},
                /*F*/ {  16,   7,   6, INF,   2,   0,   9},
                /*G*/ {  14, INF, INF, INF,   8,   9,   0}};

        //创建克鲁斯卡尔对象的实例
        KruskalAlgrothim kruskalCase = new KruskalAlgrothim(vertexs,matrix);

//        //输出构建的对象
//        kruskalCase.print();
//
//        EData[] edges = kruskalCase.getEdges();
//        System.out.println("位排序"+Arrays.toString(edges));
//        kruskalCase.sortEdges(edges);
//        System.out.println("排完顺序"+Arrays.toString(edges));


        kruskalCase.kruskal();

    }

    public KruskalAlgrothim(char[] vertexs, int[][] matrix) {
        //初始化顶点数
        int vlen = vertexs.length;

        //初始化顶点,用复制拷贝的方式
        this.vertexs = new char[vlen];
        for(int i=0;i<vertexs.length;i++){
            this.vertexs[i]=vertexs[i];
        }

        //初始化边,使用的是复制拷贝的方式
        this.matrix = new int[vlen][vlen];

        for(int i=0;i<vlen;i++){
            for(int j=0;j<vlen;j++){
                this.matrix[i][j]=matrix[i][j];
            }
        }
        //统计边
        for(int i=0;i<vlen;i++){
            for(int j=i+1;j<vlen;j++){

                if(matrix[i][j]!=INF ){
                    edgeNum++;
                }
            }
        }


    }

    public void print(){
        System.out.println("临街矩阵为\n");
        for(int i=0;i<vertexs.length;i++){
            for(int j=0;j<vertexs.length;j++){
                System.out.printf("%12d\t",matrix[i][j]);
            }
            System.out.println();
        }
    }


    //对边进行排序处理:冒泡排序
    /**
     * @param edges    边的集合
     *
     */
    private void sortEdges(EData[] edges){

        for(int i=0;i<edges.length;i++){
            for(int j=0;j<edges.length-1-i;j++){
                if(edges[j+1].weight<edges[j].weight){
                    EData temp = edges[j];
                    edges[j]=edges[j+1];
                    edges[j+1]=temp;
                }
            }
        }
    }


    /**
     *
     * @param ch  顶点的值,比如 'A' 'B'
     * @return     返回ch顶点对应的下标,如果找不到返回-1
     */
    private int getPosition(char ch){
        for(int i=0;i<vertexs.length;i++){
            if(vertexs[i]==ch){//找到
                return i;
            }
        }
        return -1;
    }


    /**
     * 功能:获取图中边,放到EData[]  数组中,后面需要遍历该数组
     * 通过martix领结矩阵来得到
     * EData[]形式 [['A','B',12],['B','F',7],...............]
     * @return
     */
    private EData[]  getEdges(){
        int  index = 0;
        EData[] edges  = new EData[edgeNum];
        for(int i=0;i<vertexs.length;i++){
            for(int j=i+1;j<vertexs.length;j++){
                if(matrix[i][j]!=INF &&matrix[i][j]!=0){//当两点构成一条边时
                    edges[index++]= new EData(vertexs[i],vertexs[j],matrix[i][j]);
                }
            }
        }
        return edges;
    }

    /**
     * 获取下标为i的顶点的终点:用于判断两个顶点的终点是否仙童
     * @param ends  记录了各个顶点对应的终点是哪个是在遍历的过程中逐步加入的;ends是在遍历过程中逐步形成的
     * @param i    表示传入顶点对应的下标
     * @return   返回的就是下标为i的这个顶点对应的终点的下标
     * 将边添加到最小生成树中时,怎么样判断是否形成了回路
     * ----->
     *          记录顶点在最小生成树的终点,顶点的终点是在“ 最小生成树中与他连通的最大顶点,然后每次需要将一条边添加到最小生成树时
     *          判断该边的两个顶点的终点是否重合,重合的haul会构成回路“
     *
     */
    private int getEnd(int[] ends,int i){
        while(ends[i]!=0){
            i=ends[i];
        }
        return i;
    }


    public void kruskal(){
        int index = 0;//表示最后结果的索引

        int[] ends = new int[edgeNum];//用于保存已有最小生成树中的每个顶点在最小生成树中的终点

        //创建结果数组,保存最后的最小生成树
        EData[] res = new EData[edgeNum];

        //获取原始图中所有的边的集合
        EData[] edges = getEdges();

        //按照边的权值大小进行排序(从小到大——
        sortEdges(edges);


        //遍历edges,将边添加到最小生成树,同时判断是否形成回路;如果没有,就加入rets,否则不能加入
        for(int i=0;i<edgeNum;i++){
            //获取到第i条边的第一个顶点
            int p1 = getPosition(edges[i].start);

            //获取到第i条边的第二个顶点
            int p2 = getPosition(edges[i].end);

            //获取p1这个顶点在最小生成树中的终点
            int m = getEnd(ends,p1);

            //获取p2这个顶点在最小生成树中的终点
            int n = getEnd(ends,p2);

            if(m!=n){//没有构成回路
                ends[m] =n;//设置m在最小生成树中的终点
                res[index++]= edges[i];//有一条边加入到results
            }

        }

        //统计并打印“最小生成树"  ,输出res
        System.out.println("最小生成树权威"+Arrays.toString(res));
    }






}


//创建EData,它的对象实例表示一条边
class EData{
    char start;//边的起点
    char end;//边的另外一个点

    int  weight;//边的权值

    public EData(char start, char end, int weight) {
        this.start = start;
        this.end = end;
        this.weight = weight;
    }

    //重新toString便于输出
    @Override
    public String toString() {
        return "EData{" +
                "start=" + start +
                ", end=" + end +
                ", weight=" + weight +
                '}';
    }
}

发布了101 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/ZHOUJIAN_TANK/article/details/103994452