資料結構 筆記:最小生成樹(Kruskal)
阿新 • • 發佈:2018-12-04
最小生成樹的特徵:
-選取的邊是圖中權值較小的邊
-所有邊連線後不構成迴路
既然最小生成樹關心的是如何選擇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演算法中的關鍵是前驅標記陣列的使用
-前驅標記陣列用於判斷選擇的邊是否會造成迴路