最小生成树之克鲁斯卡尔算法

本文将讲解生成连通图的最小生成树中的克鲁斯卡尔算法及其Java实现。

上篇博客中已经讲解了什么是最小生成树以及找连通图的最小生成树中一种经典的普里姆算法的原理和实现。有兴趣的可以浏览 http://blog.csdn.net/yz930618/article/details/77930364

克鲁斯卡尔算法原理

为使生成树上边的权值之和达到最小,则应使生成树中每一条边的权值尽可能的小。普里姆算法是以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树。而克鲁斯卡尔算法始终选择当前可用(所选的边不能构成回路)的最小权值边来构建生成树。

克鲁斯卡尔算法步骤如下:

  • 将图中的所有边都去掉。
  • 将边按权值从小到大的顺序添加到图中,保证添加的过程中不会形成环
  • 重复上一步直到连接所有顶点,此时就生成了最小生成树。

克鲁斯卡尔算法图解如下:

这里写图片描述

这里写图片描述

克鲁斯卡尔算法实现

下面是利用Java实现的克鲁斯卡尔算法。

import java.util.ArrayList;
import java.util.List;

/**
 * 最小生成树:克鲁斯卡尔算法
 */
public class MinSpanTree {

    int[][] arc;                            // 邻接矩阵

    int MAXVEX;                             // 顶点个数

    List<Edge> edges = new ArrayList<>();   // 边集数组

    int[] parent;                           // 用于判断边与边是否形成回路

    public MinSpanTree(){
        createArc(9); //生成邻接矩阵
        createEdge(9);    //生成边集数组
        createParent(9);   //生成parent数组
    }

    //生成parent数组
    private void createParent(int i) {
        parent = new int[MAXVEX];
    }

    // 生成边集数组
    private void createEdge(int i) {
        Edge v0 = new Edge(4,7,7);
        Edge v1 = new Edge(2,8,8);
        Edge v2 = new Edge(0,1,10);
        Edge v3 = new Edge(0,5,11);
        Edge v4 = new Edge(1,8,12);
        Edge v5 = new Edge(3,7,16);
        Edge v6 = new Edge(1,6,16);
        Edge v7 = new Edge(5,6,17);
        Edge v8 = new Edge(1,2,18);
        Edge v9 = new Edge(6,7,19);
        Edge v10 = new Edge(3,4,20);
        Edge v11 = new Edge(3,8,21);
        Edge v12 = new Edge(2,3,22);
        Edge v13 = new Edge(3,6,24);
        Edge v14 = new Edge(4,5,26);

        this.edges.add(v0);
        this.edges.add(v1);
        this.edges.add(v2);
        this.edges.add(v3);
        this.edges.add(v4);
        this.edges.add(v5);
        this.edges.add(v6);
        this.edges.add(v7);
        this.edges.add(v8);
        this.edges.add(v9);
        this.edges.add(v10);
        this.edges.add(v11);
        this.edges.add(v12);
        this.edges.add(v13);
        this.edges.add(v14);
    }

    // 生成邻接矩阵
    private void createArc(int index) {
        MAXVEX = index;
        arc = new int[index][index];
        this.arc[0] = new int[]{        0,       10,MAXVEX,MAXVEX,MAXVEX,       11,MAXVEX,MAXVEX,MAXVEX};
        this.arc[1] = new int[]{       10,        0,       18,MAXVEX,MAXVEX,MAXVEX,       16,MAXVEX,       12};
        this.arc[2] = new int[]{MAXVEX,MAXVEX,        0,       22,MAXVEX,MAXVEX,MAXVEX,MAXVEX,        8};
        this.arc[3] = new int[]{MAXVEX,MAXVEX,       22,        0,       20,MAXVEX,MAXVEX,       16,       21};
        this.arc[4] = new int[]{MAXVEX,MAXVEX,MAXVEX,       20,        0,       26,MAXVEX,        7,MAXVEX};
        this.arc[5] = new int[]{       11,MAXVEX,MAXVEX,MAXVEX,       26,        0,       17,MAXVEX,MAXVEX};
        this.arc[6] = new int[]{MAXVEX,       16,MAXVEX,MAXVEX,MAXVEX,       17,        0,       19,MAXVEX};
        this.arc[7] = new int[]{MAXVEX,MAXVEX,MAXVEX,       16,        7,MAXVEX,       19,        0,MAXVEX};
        this.arc[8] = new int[]{MAXVEX,       12,        8,       21,MAXVEX,MAXVEX,MAXVEX,MAXVEX,         0};
    }

    /**
     * 克鲁斯卡尔实现最小生成树
     */
    public void kruskal(){
        int i,n,m;
        int count = 0;
        for(i = 0;i < this.edges.size();i++){//遍历每一条边
            int begin = this.edges.get(i).getBegin();
            int end = this.edges.get(i).getEnd();
            n = this.find(begin);
            m = this.find(end);
            if(n != m) {//如果n不等于m,则说明没有形成回路
                count++;
                parent[n] = m;  //将此边的尾结点放入parent数组中,数组的下标表示头结点。parent[n] = m表示此顶点已经在生成树中
                System.out.println(" 第  "+count+" 条边为 : ( "+this.edges.get(i).getBegin()+" , "+ this.edges.get(i).getEnd() +" ) = "+this.edges.get(i).getWeight()+" ");
            }
        }
    }

    //查找连接顶点的尾部下标
    public int find(int f){
        while(this.parent[f] > 0){
            f = this.parent[f];
        }
        return f;
    }

    public static void main(String[] args) {
        MinSpanTree kruskal = new MinSpanTree();
        kruskal.kruskal();
    }
}

边的实体类:

public class Edge {
    private int begin;  // 边的起点
    private int end;    // 边的终点
    int weight;         // 边的权重

    public Edge(int begin, int end, int weight) {
        this.begin = begin;
        this.end = end;
        this.weight = weight;
    }

    public int getBegin() {
        return begin;
    }
    public void setBegin(int begin) {
        this.begin = begin;
    }
    public int getEnd() {
        return end;
    }
    public void setEnd(int end) {
        this.end = end;
    }
    public int getWeight() {
        return weight;
    }
    public void setWeight(int weight) {
        this.weight = weight;
    }
}

运行结果如下

这里写图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值