克鲁斯卡尔求最小生成树

和普里姆算法求最小生成树不同,普里姆算法是以顶点为中心,而克鲁斯卡尔算法是以边为中心

普里姆算法求最小生成树:https://blog.csdn.net/xindanding/article/details/90763065

克鲁斯卡尔算法有个前提,首先得将所有边按权值升序的方式存储在数组中,然后遍历数组元素,只要没有形成回路,就打印这边边

实现步骤:

 1.生成邻接矩阵【0:表示顶点到自身没有边,65535:表示两顶点之间没有边】

  结果如下:  
0           1           65535   65535   5   
1           0           2           65535   3   
65535   2           0           3           65535   
65535   65535   3           0           4   
5          3            65535   4            0  

2.实现:

图的数据结构

public class Graph {
    String[] vertex = new String[5];    //顶点类型可自定义
    int[][] edge = new int[5][5];       //边的类型可自定义

//省略get,set方法}

public class MinimunSpanningTree {
private static int edgelength = 0;     //用于存放边集数组已经存放边的数量
    /**
     * 使用克鲁斯卡尔算法实现最小生成树
     * 前提: 1.将邻接矩阵的边放入边集数组中 2,递增排序
     * @param g
     */
    public static void minimunSpan_kruskal(Graph g){
        Edge[] edges = new Edge[100];  //最多存放100条边   边集数组   可能实际只存放了50条甚至更少的边
        int adjvex[] = new int[100];  //最多存放100顶点  该数组用于存放各个生成树包含的顶点,以及各生成树组成新的生成树

//        初始化
        for(int i = 0; i < adjvex.length; i++){
            adjvex[i] = 0;
        }

        //遍历邻接矩阵并按权值升序的方式存放到边集数组中
        for(int i = 1; i < g.getVertex().length; i++){
            for(int j = 0; j < i; j++){    //无向图具有对称性,只需要遍历半三角矩阵即可,又因为顶点到自身没有边,所以对角线的边不计入
                if(g.getEdge()[i][j] > 0 && g.getEdge()[i][j] < 65535){
                    Edge edge = new Edge();
                    edge.setBegin(j);
                    edge.setEnd(i); //起点和终点的位置可以交换,此处我们按起点序号小于终点序号存放
                    edge.setWeight(g.getEdge()[i][j]);  //邻接矩阵上的值就是权值
                    insertIntoEdgeArray(edges, edge);
                }

            }
        }

        for(int k = 0; k < edgelength; k++){
            System.out.print("权值:" + edges[k].getWeight() + " ");
        }
        System.out.println();


        /**
         * 克鲁斯卡尔算法的实现部分
         */

        for(int i = 0; i < edgelength; i++){
            Edge edge = edges[i];
            int n = findAdjvex(adjvex, edge.getBegin());  //找到包含该结点的生成树的下一个位置
            int m = findAdjvex(adjvex, edge.getEnd());      //找到包含该结点的生成树的下一个位置

            if(n != m){   //如果该边的起点和终点通过findAdjvex查找结果相同,说明如果该边加入到数组会形成环
                adjvex[n] = m;
                System.out.println("权值最小边: (" + edge.getBegin() + "," + edge.getEnd() + ")");
            }
        }
    }

    /**
     * 返回包含该顶点的生成树的终点位置
     * @param adjvex
     * @param point   边的起点或终点
     * @return
     */
    private static int findAdjvex(int[] adjvex, int point){

        while(adjvex[point] != 0){
            point =  adjvex[point];
        }
        return point;
    }


    /**
     * 将该边插入到边集数组中,并排序
     * @param edges
     * @param edge
     */
    private static void insertIntoEdgeArray(Edge[] edges, Edge edge){

        /**
         *  edgelength表示数组已经存放的边数,所以只需要比较这edgelength条边
         *  如果edgelength 为0 则将边直接插入到数组中
         */
        for(int i = 0; i <= edgelength; i++) {
            Edge arrayEdge = edges[i];
            if (arrayEdge == null) {
                edges[i] = edge;
                edgelength++;   //数组存放的边 的数量加1
                break;
            } else {

                //将边插入的第i个位置
                if (arrayEdge.getWeight() >= edge.getWeight()) {
                    for (int j = edgelength; j > i; j--) {
                        edges[j] = edges[j - 1];
                    }
                    edges[i] = edge;
                    edgelength++;
                    break;
                }
            }

        }
    }
}

3.结果

权值:1 权值:2 权值:3 权值:3 权值:4 权值:5 
权值最小边: (0,1)
权值最小边: (1,2)
权值最小边: (1,4)
权值最小边: (2,3)

 

 

你可能感兴趣的:(克鲁斯卡尔求最小生成树)