克鲁斯卡尔算法

5 篇文章 0 订阅

这个算法,和普利姆算法最后想要的结果是相同的,都是为了获取通过所有点的最短路径。普利姆算法是从点开始查找,自上而下。克鲁斯卡尔算法是从边开始查找。
那么,就让我们就说一说这个算法吧!

先构造一个只含 n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中含有 n-1 条边为止。
上面内容是百度上给的基本思想,想必大家看完后也有一点小懵。

我将这个算法分为了几个步骤:
    第一,添加一个构造器,在构造器中传入点的数组和图的邻接矩阵。

private int edgeNum;
    private char[] vertexs;
    private int [][] matrix;
    private static final int INF = Integer.MAX_VALUE;//表示两个顶点不连通
    public Kruska(char[] vertexs, int[][]matrix){
        int len = vertexs.length;
        this.vertexs=vertexs;
        for(int i=0;i<len;i++){
            this.vertexs[i]=vertexs[i];
        }
        this.matrix=matrix;
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                this.matrix[i][j]=matrix[i][j];
            }
        }
    }


    第二,建立一个与边相关的类,里面含有起始点,终止点和点与点之间的距离。

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 +
                "," + end +
                ">=" + weight;
    }
}


    第三,通过图的邻接矩阵获取一共有多少条边

int len = vertexs.length;
for(int i=0;i<len;i++){
            for(int j=i+1;j<len;j++){
                if(matrix[i][j]!=10000){
                    edgeNum++;
                }
            }
        }


    第四,通过遍历邻接矩阵来获得边数组

private EData[] getEdges(){
         int index=0;
         EData[] edges = new EData[edgeNum];
         for(int i=0;i<vertexs.length;i++){
             for(int j=i+1;j<vertexs.length;j++){
                 if(matrix[i][j]!=10000){
                     edges[index++]=new EData(vertexs[i],vertexs[j],matrix[i][j]);
                 }
             }
         }
         return edges;
    }


    第五,对边数组进行排序

private void sort(EData[] edges){
        for(int i =0;i<edges.length-1;i++){
            for(int j=0;j<edges.length-1;j++){
                if(edges[j].weight>edges[j+1].weight){
                    EData temp = edges[j];
                    edges[j]=edges[j+1];
                    edges[j+1]=temp;
                }
            }
        }
    }


    第六,遍历所有的边,依次找到从小到大的边的距离。(我们在遍历所有边的时候,我们要先判断起点和终点是否在图中,接下来我们 要判断这两个点是否构成回路,如果构成回路则舍弃这条边)

private int getPosition(char ch){
        for(int i=0;i<vertexs.length;i++){
            if(vertexs[i]==ch){
                return i;
            }
        }
        return -1;
    }
private int getEnd(int[]ends,int i){
        while(ends[i]!=0){
            i=ends[i];
        }
        return i;
    }
public void kruskal(){
        int index=0;
        int[]ends=new int[edgeNum];
        EData[]rets= new EData[edgeNum];
        EData[]edges=getEdges();
        sort(edges);
        for(int i=0;i<edgeNum;i++){
            int p1=getPosition(edges[i].start);
            int p2=getPosition(edges[i].end);
            int m=getEnd(ends,p1);
            int n=getEnd(ends,p2);
            if(m!=n){
                ends[m]=n;
                rets[index++]=edges[i];
            }
        }
        for(int i=0;i<index;i++){
            System.out.println(rets[i]);
        }
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜不修

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值