最小生成樹(java)

概念:在含有n個頂點的連通網中選擇n-1條邊,構成一顆極小連通子圖,並使該連通子圖中n-1條邊上的權值之和達到最小,則稱這顆連通子圖爲連通網的最小生成樹
{
1.環境:連通網
2.選取n-1條邊
3.連通子圖
4.權值最小
}
克魯斯卡爾算法
邊按照權值遞增順序排列,循環按順序取邊,若形成環則此邊不取,修改連通分量,直到選取了n-1條邊停止循環(n爲頂點個數)
形成環的條件:起始頂點和結束頂點在同一個連通分量(子圖)中

//邊
public class Edge implements Comparable<Edge>{
    int start;    //起始頂點
    int end;      //結束頂點
    int weight;   //權值

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

    //按照權值遞增排列
    @Override
    public int compareTo(Edge o) {
        return this.weight-o.weight;
    }

    @Override
    public String toString() {
        return "Edge{" +
                "start=" + start +
                ", end=" + end +
                ", weight=" + weight +
                '}';
    }
}
//克魯斯卡爾算法
public class Kruskal {

    /**
     *
     * @param vertex 頂點集合
     * @param list 邊代表連通網
     * @return 返回最小生成子圖的邊的集合
     */
    public static List<Edge> minTree(int[] vertex, List<Edge> list){
        List<Edge> edges = new ArrayList<>();
        //按照權值遞增排序
        Collections.sort(list);
        //記錄連通分量(頂點之間有邊相連)
        ArrayList<ArrayList<Integer>> records =  new ArrayList<>();
        //記錄list的索引
        int index = 0;
        //遍歷邊集合 當選擇的邊數大於等於頂點個數-1停止循環
        while(edges.size()<vertex.length-1){
            Edge edge = list.get(index++);
            //記錄起始頂點所在連通分量索引
            int x1 = -1;
            //記錄結束頂點所在連通分量索引
            int x2 = -2;
            //遍歷records判斷是否在同一個連通分量
            for(int i = 0;i<records.size();i++){
                ArrayList<Integer> list1 = records.get(i);
                for(int j=0;j<list1.size();j++){
                    if(edge.start==list1.get(j)){
                        x1=i;
                    }
                    if(edge.end==list1.get(j)){
                        x2=i;
                    }
                }
            }
            //如果x1!=x2說明沒有形成環,修改連通分量
            if(x1!=x2){
                edges.add(new Edge(edge.start,edge.end,edge.weight));
                //雙頂點都不在連通分量中,新增連通分量
                if(x1==-1&&x2==-2){
                    ArrayList<Integer> list1 = new ArrayList<>();
                    list1.add(edge.start);
                    list1.add(edge.end);
                    records.add(list1);
                }else if(x1==-1){
                    //起始頂點不在連通分量中
                    ArrayList<Integer> list1 = new ArrayList<>();
                    list1.add(edge.start);
                    records.add(list1);
                }else if(x2==-2){
                    //結束頂點不在連通分量中
                    ArrayList<Integer> list1 = new ArrayList<>();
                    list1.add(edge.end);
                    records.add(list1);
                }else{
                    //雙頂點都在連通分量中,此時要合併v1與v2所在的連通分量
                    records.get(x1).addAll(records.get(x2));
                    records.remove(x2);
                }
            }
        }
        return edges;
    }

    public static void main(String[] args) {
        int[] vertex ={1,2,3,4,5,6};
        List<Edge> list = new ArrayList<>();
        list.add(new Edge(1,2,6));
        list.add(new Edge(1,3,1));
        list.add(new Edge(1,4,5));
        list.add(new Edge(2,3,5));
        list.add(new Edge(2,5,3));
        list.add(new Edge(3,4,5));
        list.add(new Edge(3,5,6));
        list.add(new Edge(3,6,4));
        list.add(new Edge(4,6,2));
        list.add(new Edge(5,6,6));

        List<Edge> edges1 = Kruskal.minTree(vertex, list);
        System.out.println(edges1);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章