1. 程式人生 > >資料結構 筆記:最小生成樹(Kruskal)

資料結構 筆記:最小生成樹(Kruskal)

最小生成樹的特徵:

-選取的邊是圖中權值較小的邊

-所有邊連線後不構成迴路

既然最小生成樹關心的是如何選擇n-1條邊,那麼是否可以直接以邊為核心進行演算法設計?

-由4個頂點構成圖,選擇3條權值最小的邊

如何判斷新選擇的邊與已選擇的邊是否構成迴路?

技巧:前驅標記陣列

-定義陣列:Array<int> p(vCount());

-陣列元素的意義:

·p[n]表示頂點n在邊的連線通路上的另一端頂點

最小生成樹演算法的核心步驟(Kruskal)

-定義前驅標記陣列:Array<int> p(vCount());

-獲取當前圖中的所有邊,並存儲於edges陣列中

-對陣列edges按照權值進行排序

-利用p陣列在edges陣列中選擇前n-1不構成迴路的邊

 關鍵的find查詢函式

int find(Array<int>& p,int v)
{
    while(p[v] != -1)
    {
        v = p[v];
    }
    return v;
}

SharedPointer<Array<Edge<E>>> kruskal(const bool MINMUN = true)
    {
        LinkQueue<Edge<E>> ret;
        SharedPointer <Array<Edge<E>>> edges = getUndirectedEdges();

        DynamicArray<int> p(vCount());

        for(int i = 0;i<p.length();i++)
        {
            p[i] = -1;
        }

        Sort::Shell(*edges,MINMUN );

        for(int i = 0;(i < edges->length()) && (ret.length() < (vCount() -1));i++)
        {
            int b = find(p,(*edges)[i].b);
            int e = find(p,(*edges)[i].e);

            if(b != e)
            {
                p[e] = b;

                ret.add((*edges)[i]);
            }
        }

        if(ret.length() != (vCount() -1))
        {
            //丟擲異常
        }

        return toArray(ret);

    }

總結:

-Prim演算法以頂點為核心尋找最小生成樹,不夠直接

-Kruskal演算法以邊為核心尋找最小生成樹,直觀簡單

-Kruskal演算法中的關鍵是前驅標記陣列的使用

-前驅標記陣列用於判斷選擇的邊是否會造成迴路