寻找最小生成树的kruskal算法的java实现

寻找最小生成树kruskal算法的java实现

最近几周忙着考试,这几天放假,于是,继上次关于最小生成树的实现拖到了今天。最小生成树的实现关于环的检测可以看这里

最小生成树kruskal的思想如下:

  • 1)将图中所有边按权重从小到大排序,假设放在集合G当中,结合S放即将构成最小生成树所选的边,刚开始时,结合S为空集
  • 2)逐渐选取权重最小的边,若此边与已经已经选中的边没有构成环,则放进S集合中
  • 3)重复第二步,直至S集合中的边的数量为G中(顶点数-1)

思想还是比较简单,比较好懂,废话不多说,直接上代码

  • 边的类如下
package org.wrh.algorithmdemo;
//边的类
public class Edge implements Comparable<Edge> {
    /*
     * 边的始点
     * */
    private int src;
    /*
     * 边的终点
     * */
    private int dest;
    /*
     * 边的权重
     * */
    private int weight;
    public Edge(int src, int dest,int weight) {
        super();
        this.src = src;
        this.dest = dest;
        this.weight=weight;
    }
    public int getSrc() {
        return src;
    }
    public void setSrc(int src) {
        this.src = src;
    }
    public int getDest() {
        return dest;
    }
    public void setDest(int dest) {
        this.dest = dest;
    }
    public int getWeight() {
        return weight;
    }
    public void setWeight(int weight) {
        this.weight = weight;
    }
    @Override
    public int compareTo(Edge o) {
        // TODO Auto-generated method stub
        if(this.weight<o.weight)
            return -1;
        else if(this.weight>o.weight)
            return 1;
        else
            return 0;
    }
    public String toString(){
        return "("+src+","+dest+","+weight+")"+"\n";
    }





}
  • 顶点类如下
package org.wrh.algorithmdemo;

import java.util.Arrays;
import java.util.List;



//图的类
public class Graph {
    /*
     * 图中的顶点的个数
     * */
    private int vertices_number;
    /*
     * 图中的边的个数
     * */
    private int edges_number;
    /*
     * 图中边对象的引用
     * */
    private List<Edge> edges;
    public Graph(){

    }
    public Graph(int vertices_number, int edges_number) {
        super();
        this.vertices_number = vertices_number;
        this.edges_number = edges_number;
    }
    public int getVertices_number() {
        return vertices_number;
    }
    public void setVertices_number(int vertices_number) {
        this.vertices_number = vertices_number;
    }
    public int getEdges_number() {
        return edges_number;
    }
    public void setEdges_number(int edges_number) {
        this.edges_number = edges_number;
    }
    public List<Edge> getEdge() {
        return edges;
    }
    public void setEdge(List<Edge> edge) {
        this.edges = edge;
    }
    /*
     * 功能:对图中的所有边按照边的权重按照从小到大的排序,
     * 
     * */
    public  Edge[] sort(){
        Edge [] arrayEdge=new Edge[edges.size()];
        for(int i=0;i<edges.size();i++){
            arrayEdge[i]=edges.get(i);

        }
        Arrays.sort(arrayEdge);
        return arrayEdge  ;

    }

    @Override
    public String toString() {
        StringBuffer sb=new StringBuffer();
        for(Edge edge:edges){
            sb.append("(").append(edge.getSrc()).append(",").append(edge.getDest()).append(",").append(edge.getWeight()).append(")").append("\n");

        }
        return new String(sb);
    }


}
  • 判断环的类如下
package org.wrh.algorithmdemo;

public class DisjuntSetCircle {
    /*
     * 返回true是有环的,返回false是没有环的
     * */
    public static boolean isCycle(Graph graph,int[] parent) {
        int num=graph.getEdge().size();
        int src_represent;
        int dest_represent;
        for(int i=0;i<num;i++){
            int src=graph.getEdge().get(i).getSrc();//得到边的起始点
            int dest=graph.getEdge().get(i).getDest();//得到边的终点
            src_represent=find(parent,src);
            //System.out.println("src="+src);
            dest_represent=find(parent,dest);
            //System.out.println("dest="+dest);
            if(src_represent==dest_represent){//说明,边的两个顶点已经出现在了集合中,加上此边之后,构成"环"
                return true;
            }
            else{//否则,合并
                union(parent,src_represent,dest_represent);

            }


        }
        return false;
    }


    /*
     * 合并两个不相交的集合
     * */
    private static void union(int[] parent, int src, int dest) {
        /*
         * 由于两者是两个集合的不同的"代表元素",因此将其中的的“代表元素”改为另外一个即可完成合并
         * */
        parent[src]=dest;
    }

    /*
     * 用来寻找顶点X所在集合的"代表元素"
     * */
    private static int find(int[] parent, int x) {
        /*
         * 首先判断顶点x的"代表元素是不是等于-1",若等于-1,则说明,其实一个顶点的集合,返回自身顶点的标号即可;
         * 若不等于-1,则说明此点在某个集合中,我们需找到他的代表元素的标号,即我们需要向上查找
         * */
        if(parent[x]==-1){
            return x;

        }
        return find(parent,parent[x]);
    }



}
  • 主函数类如下
package org.wrh.kruskalalg;

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

import org.wrh.algorithmdemo.DisjuntSetCircle;
import org.wrh.algorithmdemo.Edge;
import org.wrh.algorithmdemo.Graph;

//kurskal算法的java实现
/*
 * 思路如下:
 * 1)将图中所有边按权重从小到大排序,假设放在集合G当中,结合S放即将构成最小生成树所选的边,刚开始时,结合S为空集
 * 2)逐渐选取权重最小的边,若此边与已经已经选中的边没有构成环,则放进S集合中
 * 3)重复第三步,直至S集合中的边的数量为G中(顶点数-1)
 * */
public class KurskalAlgorithm {

    public static void main(String[] args) {
        /*
         * 给定边的数量和顶点的数量
         * */
        int vertices_num=9;
        int edges_num=13;
        /*
         * new一个Graph对象
         * */
        Graph graph=new Graph(vertices_num,edges_num);
        /*
         * 新建edges_num个Edge对象
         * */
        List<Edge> edge=new ArrayList<Edge>();
        edge.add(new Edge(0,1,4));
        edge.add(new Edge(0,7,8));
        edge.add(new Edge(1,7,11));
        edge.add(new Edge(1,2,8));
        edge.add(new Edge(2,3,7));
        edge.add(new Edge(2,8,2));
        edge.add(new Edge(2,5,4));
        edge.add(new Edge(3,4,9));
        edge.add(new Edge(3,5,14));
        edge.add(new Edge(4,5,10));
        edge.add(new Edge(5,6,2));
        edge.add(new Edge(6,7,1));
        edge.add(new Edge(6,8,6));


        /*
         * 将边加载到图中
         * */
        graph.setEdge(edge);//这样就构成了一个4个顶点4条边的图
        /*
         *定义parent数组来记录每个顶点属于那个集合的"代表元素";
         * 例如:我们的学生管理系统一般会记录我们的"班长"是谁一样
         * 
         * */
        /*
         * 对图中的边按照权重进行排序,返回该图边的数组
         * */
        Edge[] arrEdges=graph.sort();
        System.out.println(Arrays.toString(arrEdges));

        int parent []=new int[vertices_num];


        /*
         * 首先我们将这些集合的代表元素初始化为 -1,表示他们都是单个元素的集合
         * */
        for(int i=0;i<parent.length;i++){
            parent[i]=-1;

        }
        graph=findMST(graph,arrEdges,parent);
        System.out.println("最小生成树为:"+graph);

    }
    /*
     * graph:原图
     * arrEdges:图中所有排序后的边按升序构成的数组
     * parent:图中个顶点的“代表元素”
     * */
    private static Graph findMST(Graph graph, Edge[] arrEdges,int parent []) {
        /*
         * edgesMST用来保存图中最小生成树的所包含的边
         * */
        List<Edge> edgeList=new ArrayList<Edge>();


        /*
         * 将权重最小的边加入到最小生成树中
         * */
        edgeList.add(arrEdges[0]);
        /*
         * new一个Graph实例来保存最小生成树
         * */
        Graph graphMST=new Graph();

        /*
         * for循环限制天条件中的edgeList.size()<graph.getVertices_number()是因为MST中的边的条数等于顶点的个数减一
         * */
        for(int i=1;i<graph.getEdges_number()&&edgeList.size()<graph.getVertices_number();i++){
            /*
             * 将这条边加入到最小生成树中进行判断
             * */
            edgeList.add(arrEdges[i]);
            System.out.println("打印edgeList:"+edgeList);
            /*
             * 值得注意的是:且每次循环都要将parent清零,若不清零,将导致第二次以以后的循环的时候
             * isCircle函数中的find函数进行第一条边的源节点和目的节点的“代表元素”相等,即因有记忆错判为有环
             * 
             * 也可以选择对parent不清零,而解决方法就是,我们每次只传入新的边,然后陪和原来的parent来判断是否构成环,这种方法要更好一点
             * 具体步骤如下:
             * 我们借用一个中间图Graph graphTemp=new Graph();graphTemp.setEdge(new ArrayList(arrEdges[i]));
             * 然后将下面for循环中的graphMST换成graphTemp即可,如下
             * if(DisjuntSetCircle.isCycle(graphTemp,parent)){//如果构成环,则去掉刚刚加进来的这条边
                System.out.println("第"+i+"次有环");
                edgeList.remove(arrEdges[i]);
                //graphMST.setEdge(edgeList);//不断更新MST中的边的内容
            }
             * */
            for(int j=0;j<parent.length;j++){
                parent[j]=-1;

            }
            graphMST.setEdge(edgeList);
            if(DisjuntSetCircle.isCycle(graphMST,parent)){//如果构成环,则去掉刚刚加进来的这条边
                System.out.println("第"+i+"次有环");
                edgeList.remove(arrEdges[i]);
                //graphMST.setEdge(edgeList);//不断更新MST中的边的内容
            }

        }
        return  graphMST;

    }


}

上面代码中的注释写的比较详细,这里就不详细的解释了,以后我还是会坚持实现我们常见的一些算法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值