Java解决算法-最小生成树-克里斯卡尔算法

import java.util.*;

 

/**

 * 克鲁斯卡尔算法构造最小生成树,使用面向对象思路

 */

 

public class Task8_25_K {

    private int[][] table;

    private HashSet<Integer> V;// 存放卡鲁斯卡尔算法中已经涉及到的顶点名称

    private ArrayList<Edge> resultEdges;

    private ArrayList<Edge> initEdges;

/** 构造函数 */

    public Task8_25_K() {

       V = new HashSet<Integer>();

       resultEdges = new ArrayList<Edge>();

       initEdges = new ArrayList<Edge>();

       recordGraphic();

       createEdges();

       KRUSKAL();

//     sortInitEdges(initEdges);

       System.out.println("最小生成树由下列边组成:");

       System.out.println("顶点    权值     顶点");

       printEdge(resultEdges);

       printtable();

    }

/** 克鲁斯卡尔算法 */

    public void KRUSKAL() {

       int timer = 1;   

       sortInitEdges(initEdges);

       //这个while完毕之后还差最后一条边

       while (timer<=5){// 最小生成树的边数等于顶点数-1  

           Edge curEdge = initEdges.get(0);

           //判断是否构成环

           if(V.contains(curEdge.getLeftV()) && V.contains(curEdge.getRightV())){//构成环

              initEdges.remove(0);

              timer++;

           }

           else{//不构成环

               resultEdges.add(curEdge);

               V.add(curEdge.getLeftV());

               V.add(curEdge.getRightV());

               initEdges.remove(0);

               timer++;

           }     

       }

       resultEdges.add(findTheLastEdgeInVfromResultEdges());//自动找出最后一个边

//     resultEdges.add(initEdges.get(1));//手动加上去的,在外加最后一个边,这个地方似乎不是很妥

    }

/** 找到最后一个边,这个边跨越两个连通子树 */

    public Edge findTheLastEdgeInVfromResultEdges(){

       //此时resultEdges里面存放子树1和子树2的所有边

       ArrayList<Integer> setA = new ArrayList<Integer>();//存放子树1的顶点

       ArrayList<Integer> setB = new ArrayList<Integer>();//存放子树2的顶点

        ArrayList<Edge> tempEdges = new ArrayList<Edge>();//临时在两子树间构架边

       

       setA.add(resultEdges.get(0).getLeftV());//子树1初始化

       setA.add(resultEdges.get(0).getRightV());//子树1初始化

       for(int i=1;i<resultEdges.size();i++){//遍历前面棵子树的所有边

           Edge edge = resultEdges.get(i);//获得当前遍历的边的引用

           if(setA.contains(edge.getLeftV()) || setA.contains(edge.getRightV())){

              setA.add(resultEdges.get(i).getLeftV());//如果当前边的两顶点有任何一个存在于setA

               setA.add(resultEdges.get(i).getRightV());//即将两顶点放入setA

           }

           else{

              setB.add(resultEdges.get(i).getLeftV());//否则放入到setB

               setB.add(resultEdges.get(i).getRightV());

           }

       }

       for(int i=0;i<setA.size();i++)//按照table建临时的边(这些边跨越setA setB

           for(int j=0;j<setB.size();j++)

              if(table[setA.get(i)][setB.get(j)] > 0)

                  tempEdges.add(new Edge(setA.get(i),table[setA.get(i)][setB.get(j)],setB.get(j)));

       Collections.sort(tempEdges);//根据权值非递减排序

       return tempEdges.get(0);//返回全职最小的边的引用

    }

   

    /** 打印边的集合 */

    public void printEdge(ArrayList<Edge> edges){

       Iterator <Edge> it = edges.iterator();

       while(it.hasNext()){

           Edge edge = it.next();

           System.out.println(edge);

       }

    }

    /** 对边根据权值非递减排序 */

    public void sortInitEdges(ArrayList<Edge> edges) {

       Collections.sort(edges);

    }

 

    /** 创建所有边 */

    public void createEdges() {

       for (int i = 1; i < table.length; i++) {

           for (int j = i; j < table[i].length; j++)

              if (table[i][j] > 0)

                  initEdges.add(new Edge(i, table[i][j], j));

       }

    }

 

    /** 记录图信息 */

    public void recordGraphic() {

 

       table = new int[][] { { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 6, 2, 0, 0 },

              { 0, 0, 0, 7, 2, 0, 0 }, { 0, 0, 0, 0, 9, 4, 3 },

              { 0, 0, 0, 0, 0, 7, 6 }, { 0, 0, 0, 0, 0, 0, 3 },

              { 0, 0, 0, 0, 0, 0, 0 } };

       for (int i = 1; i < table.length; i++)

           for (int j = i + 1; j < table.length; j++)

              table[j][i] = table[i][j];

    }

   

    /** 打印图信息 */

    public void printtable() {

       System.out.println("");

       System.out.println("图的信息:");

       for (int i = 1; i < table.length; i++) {

           for (int j = 1; j < table.length; j++) {

              System.out.printf("%3d", table[i][j]);

           }

           System.out.print("/n");

       }

    }

   

    public static void main(String[] args) {

       new Task8_25_K();

    }

}

 

class Edge implements Comparable<Object> {//边类 实现comparable接口方便排序

    private int length;// 边的长度

    private int leftV;// 边的一个顶点的名字

    private int rightV;// 边的另一个定点的名字

 

    public int getLength() {

       return length;

    }

 

    public void setLength(int length) {

       this.length = length;

    }

 

    public int getLeftV() {

       return leftV;

    }

 

    public void setLeftV(int leftV) {

       this.leftV = leftV;

    }

 

    public int getRightV() {

       return rightV;

    }

 

    public void setRightV(int rightV) {

       this.rightV = rightV;

    }

 

    public Edge(int leftV, int length, int rightV) {

       this.leftV = leftV;

       this.length = length;

       this.rightV = rightV;

    }

 

    public Edge() {

 

    }

 

    @Override

    public int compareTo(Object e) {

       if (((Edge) e).length > this.length)

           return -1;

       else if (((Edge) e).length == this.length)

           return 0;

       else

           return 1;

    }

 

    public String toString(){

       return (this.leftV+"<----"+this.length+"---->"+this.rightV);

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值