贪心算法_最小生成树_Kruskal(克鲁斯卡尔)算法

/**
 * 8.贪心算法_最小生成树_Kruskal(克鲁斯卡尔)算法
 * @author Matt
 */
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;

public class Kruskal {
    /**
     * 创建一个Edge边类
     * @author Matt
     */
    public static class Edge implements Comparable {
        // 分别代表起始节点、终止节点、权值
        int u, v, w;
        // 构造器
        public Edge(int u, int v, int w) {
            this.u = u;
            this.v = v;
            this.w = w;
        }

        @Override
        // 排序,按权值从小到大排序
        public int compareTo(Edge o) {
            int ow = o.w;
            if (w < ow)
                return -1;
            if (w == ow)
                return 0;
            return 1;
        }

    }

    /**
     * 克鲁斯卡尔算法
     * @param V 序号
     * @param E 边节点
     */
    public static void Kruskal(int[] V, Edge[] E) {
        Arrays.sort(E);// 将边按照权重w升序排序
        // 创建一个ArrayList容器来保存所有边的表集合
        ArrayList sets = new ArrayList();
        // 从0到6进行遍历
        for (int i = 0; i < V.length; i++) {
            // 创建一个哈希表
            HashSet set = new HashSet();
            // 从1开始设置边的序号,一共5个边
            set.add(V[i]);
            // 将表添加到容器中
            sets.add(set);
        }
        // 遍历每一条边
        for (int i = 0; i < E.length; i++) {
            // 取出每一个边节点的起始位置和终止位置
            int start = E[i].u, end = E[i].v;
            // 有些节点之间不同,赋为负值
            int counti = -1, countj = -2;
            // 从0到6遍历容器
            for (int j = 0; j < sets.size(); j++) {
                // 取出容器中每一个边的表
                HashSet set = sets.get(j);
                // 如果存在数据,counti赋值为起始节点
                if (set.contains(start)) {
                    counti = j;
                }
                // 如果存在数据,countj赋值为终止节点
                if (set.contains(end)) {
                    countj = j;
                }
            }
            // 若为负值则错误
            if (counti < 0 || countj < 0)
                System.err.println("没有在子树中找到节点,错误");
            // 起始节点和终止节点不为同一个
            if (counti != countj) {
                // 打印路径
                System.out.println(
                        "start = " + start + 
                        ", end = " + end + 
                        ", weight = " + E[i].w);
                // 从容器中取出序号为终止节点的边
                HashSet setj = sets.get(countj);
                sets.remove(countj); // 移除该边
                // 从容器中取出序号为起始节点的边
                HashSet seti = sets.get(counti);
                sets.remove(counti); // 移除该边
                // 设置起始节点为终止节点(进行两点连接)
                seti.addAll(setj);
                // 将该边添加至容器
                sets.add(seti);
            } 
        }

    }

    public static void main(String[] args) {
        // 初始化
        int[][] tree = { 
                { -1, 6, 1, 5, -1, -1 }, 
                { 6, -1, 5, -1, 3, -1 }, 
                { 1, 5, -1, 5, 6, 4 },
                { 5, -1, 5, -1, -1, 2 }, 
                { -1, 3, 6, -1, -1, 6 }, 
                { -1, -1, 4, 2, 6, -1 } };
        // 创建V和E数组
        int[] V = { 1, 2, 3, 4, 5, 6 };
        Edge[] E = new Edge[10];
        E[0] = new Edge(1, 2, 6);
        E[1] = new Edge(1, 3, 1);
        E[2] = new Edge(1, 4, 5);
        E[3] = new Edge(2, 3, 5);
        E[4] = new Edge(2, 5, 3);
        E[5] = new Edge(3, 4, 5);
        E[6] = new Edge(3, 5, 6);
        E[7] = new Edge(3, 6, 4);
        E[8] = new Edge(4, 6, 2);
        E[9] = new Edge(5, 6, 6);
        Kruskal(V, E);
    }
}
// 运行结果:
//  start = 1, end = 3, weight = 1
//  start = 4, end = 6, weight = 2
//  start = 2, end = 5, weight = 3
//  start = 3, end = 6, weight = 4
//  start = 2, end = 3, weight = 5

你可能感兴趣的:(Java)