資料結構 筆記:最小生成樹(prim)
阿新 • • 發佈:2018-12-01
運營商的挑戰
-在下圖標出的城市間架設一條通訊線路
要求:
·任意兩個城市間都能夠通訊
·將架設成本呢將至最低
如何在圖中選擇n-1條邊使得n個頂點間兩兩可達,並且這n-1條邊的權值之和最小
最小生成樹
-僅使用圖中的n-1條邊連線圖中的n個頂點
-不能使用產生迴路的邊
-個邊上的權值的總和達到最小
最小生成樹演算法步驟
-選擇某一頂點V0作為起始頂點,是的T={V0},F={V1,V2,...Vn},E={ }
-每次選擇一條邊,這條邊是所有(u,v)中權值最小的邊,且u屬於T,v屬於F
-修改T,F,E:
T = T + {v} ,F = F - {v}, E = E + {(u,v)}
-當F != NULL是,切(u,v)存在,轉2;否則,結束
最小生成樹演算法的原材料
型別 | 變數 | 用途 |
Array<bool> | mark | 標記頂點所屬的集合(T or F) |
Array<E> | cost | 記錄T集合到F集合中頂點的最小權值 |
Array<int> | adjVex | 記錄cost中權值的對應頂點 |
Queue<Edge> | ret | 記錄最小生成樹中的邊 |
注意事項
-最小生成樹僅針對無向圖有意義
-必須判斷圖物件是否能夠看做無向圖
圖型別(Graph)中的新增成員函式
-virtual bool isAdjacent (int i,int j) = 0;
-bool assUndirected();
·判斷當前的有向圖是否能夠看做無向圖
bool isAdjacent(int i ,int j) { return (0 <= i) && ( i < vCount()) && ( 0 <= j) && (j < vCount()) && (m_list.get(i)->edge.find(Edge<E>(i,j)) >=0); } bool asUndirected() { bool ret = true; for(int i = 0;i<vCount() ; i++) { for(int j = 0;j<vCount();j++) { if(isAdjacent(i,j)) { ret = ret && isAdjacent(j,i) && (getEdge(i,j) == getEdge(j,i)); } } } return ret; } SharedPointer <Array <Edge <E> >> prim( const E& LIMIT,const bool MINIMUM = true) { LinkQueue<Edge<E>> ret; if(asUndirected()) { DynamicArray<int> adjVex(vCount()); DynamicArray<bool> mark(vCount()); DynamicArray<E> cost(vCount()); SharedPointer<Array<int>> aj = NULL; bool end = false; int v = 0; for(int i = 0;i<vCount() ; i++) { adjVex[i] = -1; mark[i] = false; cost[i] = LIMIT; } mark[v] = true; aj = getAdjacent(v); for(int j = 0;j < aj->length();j++) { cost[(*aj)[j]] = getEdge(v,(*aj)[j]); adjVex[(*aj)[j]] = v; } for(int i = 0;(i<vCount()) && !end;i++) { E m = LIMIT; int k = -1; for(int j = 0;j<vCount();j++) { if( !mark[j] && (MINIMUM ?(cost[j] < m) :(cost[j] > m))) { m = cost[j]; k = j; } } end = (k == -1); if(!end) { ret.add(Edge<E>(adjVex[k],k,getEdge(adjVex[k],k))); mark[k] = true; aj = getAdjacent(k); for(int j = 0;j<aj->length();j++) { if(!mark[(*aj)[j]] && (MINIMUM ? (getEdge(k,(*aj)[j]) < cost[(*aj)[j]]):(getEdge(k,(*aj)[j]) > cost[(*aj)[j]]))) { cost[(*aj)[j]] = getEdge(k,(*aj)[j]); adjVex[(*aj)[j]] = k; } } } } } else { //丟擲異常 } if(ret.length() != (vCount() -1)) { //丟擲異常 } return toArray(ret); }
總結:
-最小生成樹使得頂點間的連通代價最小
-Prim演算法通過頂點的動態標記尋找最小生成樹
-Prim演算法的關鍵是集合概念的援用(T 集合,F 集合)
-利用Prim演算法的思想也能尋找圖的“最大生成樹”