最小生成樹-克魯斯卡爾算法(kruskal's algorithm)實現


算法描述

克魯斯卡爾算法是一種貪心算法,因為它每一步都挑選當前最輕的邊而並不知道全局路徑的情況.
算法最關鍵的一個步驟是要判斷要加入mst的頂點是否會形成回路,我們可以利用並查集的技術來做。

並查集的具體實現可參考:快速並查集

下面是對算法的一個簡單描述:
kruskal

這是一個非常簡單易懂的算法,它面向邊而不是頂點,所以在算法開始的時候,它要先找出所有的crossing edges,而為了高效的找到最輕邊,用一個優先隊列來維護這些crossing edges.

    /** * 找出所有crossing edges並加入優先隊列 */
    private void findAllCrossingEdges(){
        for(Vertex v:this.vertices) {
            for(Edge edge:v.Adj) {
                WeightedEdge we = (WeightedEdge)edge;
                this.crossingEdges.add(we);
            }
        }
    }
    private PriorityQueue<WeightedEdge> crossingEdges = new PriorityQueue<WeightedEdge>();

算法實現

下面是克魯斯卡爾算法的一個實現:

    /** * 克魯斯卡爾算法求MST * * 克魯斯爾卡算法也是一種貪心算法(greedy algorithm) * 1.總是挑選最輕的邊,如果這條邊的兩個端點沒有形成回路,就將這條邊加入MST * 2.在剩下的邊中,重復1. * */
    public void kruskalMST() {
        resetMemo();
        //找出所有crossing edges
        findAllCrossingEdges();
        //初始化並查集
        FastUnionFind uf = new FastUnionFind(vertexCount());
        //算法用貪心策略,每一步都挑選最輕的邊來加入mst
        //需要注意的是,在加入mst之前要考察邊的兩端頂點是否形成環路
        while (!this.crossingEdges.isEmpty()) {
            //最輕邊
            WeightedEdge edge = crossingEdges.poll();
            //如果點src和點to沒有形成環
            if(!uf.isConnected(edge.src,edge.to)){
                //將src和to連通
                uf.union(edge.src,edge.to);
                //將最輕邊加入mst
                mst.offer(edge);
                //更新mst的權重
                mstWeight += edge.weight;
            }
        }
    }

時間復雜度

算法需要對所有邊E 進行訪問,這步操作耗時O(E )
將邊入隊和出隊的操作耗時O(logE).
由於假設圖是連通的,並查判斷回路操作耗時O(logE)
所以整體耗時O(ElogE ).
由於 |E| < V*V,所以logE = 2logV,則可將算法復雜度寫為O(ElogV).


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM