2020-09-07

**

克鲁斯卡尔算法

**

克鲁斯卡尔算法是求连通网的最小生成树的另一种方法。与普里姆算法不同,它的时间复杂度为O(eloge)(e为网中的边数),所以,适合于求边稀疏的网的最小生成树 。

克鲁斯卡尔(Kruskal)算法从另一途径求网的最小生成树。其基本思想是:假设连通网G=(V,E),令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点分别在T中不同的连通分量上,则将此边加入到T中;否则,舍去此边而选择下一条代价最小的边。依此类推,直至T中所有顶点构成一个连通分量为止

例:

在这里插入图片描述
思路:

在这里插入图片描述
在这里插入图片描述

实现代码:

package com.algorithm;

import java.util.Arrays;

public class KruskaAlgorithm {
    private char[] vertxs;//创建顶点数组
    private int[][] martix;//创建邻接矩阵
    private int edgesNum;//定义边的个数
    private static final int INF = Integer.MAX_VALUE;


    public static void main(String[] args) {
        char[] vertex = {'A','B','C','D','E','F','G'};
        int[][] martix ={
                {0,12,INF,INF,INF,16,14},
                {12,0,10,INF,INF,7,INF},
                {INF,10,0,3,5,6,INF},
                {INF,INF,3,0,4,INF,INF},
                {INF,INF,5,4,0,2,8},
                {16,7,6,INF,2,0,9},
                {14,INF,INF,INF,8,9,0}
        };
        KruskaAlgorithm kruskaAlgorithm = new KruskaAlgorithm(vertex, martix);
        kruskaAlgorithm.display();
        EData[] edges1 = kruskaAlgorithm.getEdges();
        kruskaAlgorithm.kruskal();

    }

    //创建Kruskal算法
    public void kruskal()
    {
        int index = 0;//定义一个数组索引
        int[] ends = new int[edgesNum];//用于保存已有的最小生成树的每个顶点在最小生成树中的终点
        EData[] res = new EData[edgesNum];//创建结果数组,用于保存最后的最小生成树
        //获取图中的所有边的结合
        EData[] edges = getEdges();
        //按照边的权值进行排序
        sort(edges);
        //遍历edges数组,将边添加到最小生成树中,并且判断下次准备加入的边是否构成了回路,没有才可以加入
        for (int i = 0; i < edgesNum; i++) {
            //获取第i条边的起点
            int p1 = getPosition(edges[i].start);
            //获取第i条边的终点
            int p2 = getPosition(edges[i].end);
            //获取p1顶点在已有最小生成树的终点
            int m = getEnd(ends,p1);
            //获取p2顶点在已有最小生成树的终点
            int n = getEnd(ends,p2);
            //判断是否构成回路
            if (m != n)//此时没有构成回路
            {
                ends[m] = n;
                res[index++] = edges[i];
            }
        }
        for (int i = 0; i < index; i++) {
            System.out.println(res[i]);
        }

    }


    //创建构造器来初始化邻接矩阵
    public KruskaAlgorithm(char[] vertxs,int[][] martix)
    {
        int vLen = vertxs.length;
        this.vertxs = new char[vLen];
        //初始化顶点vertxs
        for (int i = 0; i < vLen; i++) {
            this.vertxs[i] = vertxs[i];
        }

        this.martix = new int[vLen][vLen];
        //初始化邻接矩阵
        for (int i = 0; i < vLen; i++) {
            for (int j = 0; j < vLen; j++) {
                this.martix[i][j] = martix[i][j];
            }
        }
        //统计有多少条边
        for (int i = 0; i < vLen; i++) {
            for (int j = i + 1; j < vLen; j++) {
                if (this.martix[i][j] != INF )
                    edgesNum++;
            }
        }
    }

    //打印邻接矩阵
    public void display()
    {
        System.out.println("打印邻接矩阵:");
        for (int i = 0; i < vertxs.length; i++) {
            for (int j = 0; j < vertxs.length; j++) {
                System.out.printf("%14d", martix[i][j]);
            }
            System.out.println();
        }
    }

    //对每条边的权值进行冒泡排序
    public void sort(EData[] eData)
    {
        EData tmp;
        for (int i = 0; i < eData.length - 1; i++) {
            for (int j = 0; j < eData.length - 1 -i; j++) {
                if (eData[i].weight < eData[j].weight)
                {
                  tmp = eData[i];
                  eData[i] = eData[j];
                  eData[j] = tmp;
                }
            }
        }
    }

    //寻找顶点的对应的索引
    private int getPosition(char ch)
    {
        for (int i = 0; i < vertxs.length; i++) {
            if (vertxs[i] == ch)
                return i;
        }
        return -1;
    }

    //寻找每条边的,放入数组EData中,
    private EData[] getEdges()
    {
        int index = 0;//建立索引,方便等下进行存储操作
        EData[] eData = new EData[edgesNum];//新建EData数组
        //遍历操作每条边,当边存在时,保存
        for (int i = 0; i < vertxs.length; i++) {
            for (int j = i + 1; j < vertxs.length; j++) {
                if (martix[i][j] != INF)
                {
                    eData[index++] = new EData(vertxs[i],vertxs[j],martix[i][j]);
                }
            }
        }
        return eData;
    }

    /*获取下标为i的顶点的终点
        用于判断后面两个顶点的终点是否相同
        ends(每次加入的ends是动态加入的,记录各个顶点的终点是哪个)
        i:表示传入顶点对应的下标
        返回的是下标为i的这个顶点对应的终点的下标


     */
    private int getEnd(int[] ends,int i)
    {
        while (ends[i] != 0)
            i = ends[i];
        return i;
    }



}

class EData
{
    char start;//边上的起点
    char end;//边上的终点
    int weight;//此边的权值

    public EData(char start, char end, int weight) {
        this.start = start;
        this.end = end;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "EData{" +
                "start=" + start +
                ", end=" + end +
                ", weight=" + weight +
                '}';
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值