MST的Prim与Kruskal算法(第一次作业)

一.问题
  1. 举一个实例,画出采用Prim算法构造最小生成树的过程,并按实验报告模板编写算法。
  2. 举一个实例,画出采用Kruskal算法构造最小生成树的过程,并按实验报告模板编写算法。
二.解析

Prim算法图解
Prim算法
Kruskal算法图解
Kruskal算法

3.设计

Prim算法

/**
 * @Description MST的Prim算法
 * @Author ZhengLing
 * @Date 2021/03/15 21:36
 */
import java.util.Arrays;
import java.util.Scanner;

public class Prim {
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n =  scanner.nextInt();
        int m = scanner.nextInt();
        int[][] cost = new int[n+1][n+1];
        for(int i = 1; i<n+1; i++){
            Arrays.fill(cost[i], Integer.MAX_VALUE);
        }
        for(int i = 0; i<m; i++){
            int x = scanner.nextInt();
            int y = scanner.nextInt();
            int p = scanner.nextInt();
            cost[x][y] = cost[y][x] = p;
        }
        prim(cost, n, Integer.MAX_VALUE);
    }

    public static void prim(int[][] cost, int n, int maxi){
        int[] lowcost = new int[n+1];
        int[] closest = new int[n+1];

        for(int i = 2; i<n+1; i++){
            lowcost[i] = cost[1][i];
            closest[i] = 1;
        }
        int min, m;
        //寻找邻近最小路径
        for(int i = 2; i<n+1; i++){
            min = maxi;
            m = 1;
            for(int j = 2; j<n+1; j++){
                if(lowcost[j] < min && lowcost[j] != 0){
                    m = j;
                    min = lowcost[j];
                }
            }
            //输出生成树的边
            System.out.println("closest[" + m + "]=" + closest[m]);
            lowcost[m] = 0;
            closest[m] = 0;
            //调整代价
            for(int j = 2; j<n+1; j++){
                if(cost[m][j] < lowcost[j] && cost[m][j] != 0){
                    lowcost[j] = cost[m][j];
                    closest[j] = m;
                }
            }
        }
    }
}

Kruskal算法

/**
 * @Description MST的Kruskal算法
 * @Author ZhengLing
 * @Date 2021/03/15 21:39
 */

import java.util.ArrayList;
import java.util.Scanner;

public class Kruskal {
    
    static class Edge {
        public int a;// 开始顶点
        public int b;   //结束顶点
        public int value;   //权值

        Edge(int a, int b, int value) {
            this.a = a;
            this.b = b;
            this.value = value;
        }
    }
    //使用合并排序,把数组A按照其value值进行从小到大排序
    public void edgeSort(Edge[] A){
        if(A.length > 1) {
            Edge[] leftA = getHalfEdge(A, 0);
            Edge[] rightA = getHalfEdge(A, 1);
            edgeSort(leftA);
            edgeSort(rightA);
            mergeEdgeArray(A, leftA, rightA);
        }
    }
    //judge = 0返回数组A的左半边元素,否则返回右半边元素
    public Edge[] getHalfEdge(Edge[] A, int judge) {
        Edge[] half;
        if(judge == 0) {
            half = new Edge[A.length / 2];
            for(int i = 0;i < A.length / 2;i++) {
                half[i] = A[i];
            }
        } else {
            half = new Edge[A.length - A.length / 2];
            for(int i = 0;i < A.length - A.length / 2;i++) {
                half[i] = A[A.length / 2 + i];
            }
        }
        return half;
    }
    //合并leftA和rightA,并按照从小到大顺序排列
    public void mergeEdgeArray(Edge[] A, Edge[] leftA, Edge[] rightA) {
        int i = 0;
        int j = 0;
        int len = 0;
        while(i < leftA.length && j < rightA.length) {
            if(leftA[i].value < rightA[j].value) {
                A[len++] = leftA[i++];
            } else {
                A[len++] = rightA[j++];
            }
        }
        while(i < leftA.length) {
            A[len++] = leftA[i++];
        }
        while(j < rightA.length) {
            A[len++] = rightA[j++];
        }
    }

    //获取节点a的根节点编号
    public int find(int[] id, int a) {
        int i, root, k;
        root = a;
        while(id[root] >= 0) {
            root = id[root];  
        }
        k = a;
        while(k != root) {  
            i = id[k];
            id[k] = root;
            k = i;
        }
        return root;
    }
   
    public void union(int[] id, int a, int b) {
        int ida = find(id, a);   
        int idb = find(id, b);  
        int num = id[ida] + id[idb];  
        if(id[ida] < id[idb]) {
            id[idb] = ida;    
            id[ida] = num;   
        } else {
            id[ida] = idb;   
            id[idb] = num;    
        }
    }
    
    public ArrayList<Edge> getMinSpanTree(int n, Edge[] A) {
        ArrayList<Edge> list = new ArrayList<Edge>();
        int[] id = new int[n];
        for(int i = 0;i < n;i++) {
            id[i] = -1;        
        }
        edgeSort(A);   
        int count = 0;
        for (Kruskal.Edge edge : A) {
            int a = edge.a;
            int b = edge.b;
            int ida = find(id, a - 1);
            int idb = find(id, b - 1);
            if (ida != idb) {
                list.add(edge);
                count++;
                union(id, a - 1, b - 1);
            }

            for (int i : id) {
                System.out.print(i + " ");
            }
            System.out.println();

            if (count >= n - 1) {
                break;
            }
        }
        return list;
    }

    public static void main(String[] args){
        Kruskal test = new Kruskal();
        Scanner in = new Scanner(System.in);
        System.out.println("请输入顶点数a和具体边数p:");
        int n = in.nextInt();
        int p = in.nextInt();
        Edge[] A = new Edge[p];
        System.out.println("请依次输入具体边对于的顶点和权值:");
        for(int i = 0;i < p;i++) {
            int a = in.nextInt();
            int b = in.nextInt();
            int value = in.nextInt();
            A[i] = new Edge(a, b, value);
        }
        ArrayList<Edge> list = test.getMinSpanTree(n, A);
        System.out.println("使用Kruskal算法得到的最小生成树具体边和权值分别为:");
        for (Kruskal.Edge edge : list) {
            System.out.println(edge.a + "——>" + edge.b + ", " + edge.value);
        }
    }
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值