贪心算法:最小生成树

假设无向图为:

A-B:1

A-C:3

B-C:1

B-D:4

C-D:1

C-E:5

D-E:6

一、使用Prim算法:

java 复制代码
public class Prim {
    //声明了两个静态常量,用于辅助 Prim 算法的实现
    private static final int V = 5;//点数
    private static final int INF = Integer.MAX_VALUE;//若直接使用 0 表示无边,会与边权为 0 的情况冲突。而 Integer.MAX_VALUE 是一个极大的值,在比较边权时不会被误认为有效边权。

    public static void main(String[] args){
        int [][] graph = new int[][]{
                {0, 1, 3, 0, 0},
                {1, 0, 1, 4, 0},
                {3, 1, 0, 1, 5},
                {0, 4, 1, 0, 6},
                {0, 0, 5, 6, 0}
        };//用二维数组表示无向图

        primMST(graph);
    }

    private static void primMST(int[][] graph) {
        int[] parent = new int[V];//记录每个结点的父节点
        int[] key = new int[V];//记录每个结点当前最小边权
        boolean[] mstSet = new boolean[V];//标记顶点是否已被加入MST

        for(int i =0;i<V;i++){
            key[i] = INF;
            mstSet[i] = false;
        }//初始化
        key[0] = 0;
        parent[0] = -1;
        //初始化
        for(int count =0;count<V-1;count++){
            int u = minKey(key,mstSet);//从未加入 MST 的顶点中选择 key 值最小的顶点 u
            mstSet[u] = true;//将 u 加入 MST
//遍历所有与 u 相邻的顶点 v:
//如果 v 未被加入 MST 且边 (u, v) 的权值小于 v 的当前 key,则更新 v 的 key 和 parent。
            for(int v=0;v<V;v++){
                if(graph[u][v] != 0&&mstSet[v]==false&&graph[u][v] < key[v]){
                    parent[v] = u;
                    key[v] = graph[u][v];
                }
            }
        }
        printMST(parent,graph);
    }
//打印结果
    private static void printMST(int[] parent, int[][] graph) {
        System.out.println("Edge \tWeight");
        for (int i = 1; i < V; i++) {
            System.out.println(parent[i] + " - " + i + "\t" + graph[i][parent[i]]);
        }
    }

    private static int minKey(int[] key, boolean[] mstSet) {
        int min = INF,minIndex = -1;
        //初始化
        for(int v = 0;v<V;v++){
            if(mstSet[v]==false && key[v]<min){
                min = key [v];
                minIndex = v;
            }
        }
        return minIndex;
    }

}

二、使用Kruskal算法:

java 复制代码
import java.util.*;

public class Kruskal{
    private static final int V = 5; // Number of vertices in the graph
    private Edge[] edges; // 存储所有边,包含三个成员变量:src(源顶点)、dest(目标顶点)和 weight(边的权重)。
    private int edgeCount = 0; // 边的数量

    class Edge implements Comparable<Edge> {
        int src, dest, weight;

        public int compareTo(Edge compareEdge) {
            return this.weight - compareEdge.weight;
        }
    }
//用于实现并查集
    class subset {
        //用于跟踪每个顶点的父节点和秩
        int parent, rank;
    }
//查找顶点 i 的根节点,并实现路径压缩
    int find(subset[] subsets, int i) {
        if (subsets[i].parent != i) {
            subsets[i].parent = find(subsets, subsets[i].parent);
        }
        return subsets[i].parent;
    }
//合并两个子集,使用秩来保持树的平衡
    void Union(subset[] subsets, int x, int y) {
        int xroot = find(subsets, x);
        int yroot = find(subsets, y);

        if (subsets[xroot].rank < subsets[yroot].rank) {
            subsets[xroot].parent = yroot;
        } else if (subsets[xroot].rank > subsets[yroot].rank) {
            subsets[yroot].parent = xroot;
        } else {
            subsets[yroot].parent = xroot;
            subsets[xroot].rank++;
        }
    }

    public static void main(String[] args) {
        int[][] graph = new int[][]{
                {0, 1, 3, 0, 0},
                {1, 0, 1, 4, 0},
                {3, 1, 0, 1, 5},
                {0, 4, 1, 0, 6},
                {0, 0, 5, 6, 0}
        };

        Kruskal kruskal = new Kruskal();
        kruskal.kruskalMST(graph);
    }

    void kruskalMST(int[][] graph) {
        // 计算边的数量并初始化edges数组
        int edgeCount = 0;
        //初始化
        for (int i = 0; i < V; i++) {
            for (int j = i + 1; j < V; j++) {
                if (graph[i][j] != 0) {
                    edgeCount++;
                }
            }
        }
        edges = new Edge[edgeCount];
        edgeCount = 0;

        // 初始化边数组
        for (int i = 0; i < V; i++) {
            for (int j = i + 1; j < V; j++) {
                if (graph[i][j] != 0) {
                    edges[edgeCount] = new Edge();
                    edges[edgeCount].src = i;
                    edges[edgeCount].dest = j;
                    edges[edgeCount].weight = graph[i][j];
                    edgeCount++;
                }
            }
        }

        // 步骤1: 按权重升序排列边
        Arrays.sort(edges);

        // 步骤2: 初始化子集
        subset[] subsets = new subset[V];
        for (int i = 0; i < V; i++) {
            subsets[i] = new subset();
            subsets[i].parent = i;
            subsets[i].rank = 0;
        }

        // 步骤3: 用于存储MST的边
        Edge[] result = new Edge[V - 1];
        int e = 0; // 结果数组的索引
        int i = 0; // 排序后边的索引

        // 步骤4: 遍历每条边并添加到MST中(如果不形成环)
        while (e < V - 1 && i < edges.length) {
            Edge next_edge = edges[i++];

            int x = find(subsets, next_edge.src);
            int y = find(subsets, next_edge.dest);

            if (x != y) {
                result[e++] = next_edge;
                Union(subsets, x, y);
            }
        }

        // 输出结果
        System.out.println("Following are the edges in the constructed MST");
        for (i = 0; i < e; i++) {
            System.out.println(result[i].src + " -- " + result[i].dest + " == " + result[i].weight);
        }
    }
}
相关推荐
万能程序员-传康Kk2 小时前
旅游推荐数据分析可视化系统算法
算法·数据分析·旅游
PXM的算法星球2 小时前
【并发编程基石】CAS无锁算法详解:原理、实现与应用场景
算法
ll7788112 小时前
C++学习之路,从0到精通的征途:继承
开发语言·数据结构·c++·学习·算法
烨然若神人~2 小时前
算法第十七天|654. 最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树
算法
爱coding的橙子2 小时前
每日算法刷题Day2 5.10:leetcode数组1道题3种解法,用时40min
算法·leetcode
Panesle3 小时前
分布式异步强化学习框架训练32B大模型:INTELLECT-2
人工智能·分布式·深度学习·算法·大模型
多多*3 小时前
算法竞赛相关 Java 二分模版
java·开发语言·数据结构·数据库·sql·算法·oracle
逐光沧海3 小时前
数据结构基础--蓝桥杯备考
数据结构·c++·算法·蓝桥杯
Kidddddult4 小时前
力扣刷题Day 48:盛最多水的容器(283)
算法·leetcode·力扣