好久, 沒寫blog了,今天,多寫點。
上節說到那裡了,是不是說圖的遍歷,這節,我們來通過圖的具體的應用了。
首先,看看最小生成樹的應用了。 什麼是最小生成樹了?
由生成樹的定義可知,無向連通圖的生成樹不是唯一的,對連通圖的不同遍歷就得到不同的生成樹。圖 b 所示是圖 (a)所示的無向連通圖的部分生成樹。
所謂最小生成樹是 如果是乙個無向連通網, 那麼它的所有生成樹中必有一棵邊的權值總和最小的生成樹,我們稱這棵生成樹為最小代價生成樹(minimum cost spanning tree).
許多應用問題都是乙個求無向連通網的最小生成樹問題。例如,要在 n個城市之間鋪設光纜, 鋪設光纜的費用很高, 並且各個城市之間鋪設光纜的費用不同。乙個目標是要使這 n個城市的任意兩個之間都可以直接或間接通訊, 另乙個目標是要使鋪設光纜的總費用最低。如果把 n個城市看作是圖的 n個頂點,兩個城市之間鋪設的光纜看作是兩個頂點之間的邊, 這實際上就是求乙個無向連通網的最小生成樹問題。
由最小生成樹的定義可知, 構造有 n個頂點的無向連通網的最小生成樹必須滿足以下三個條件:
(1)構造的最小生成樹必須包括 n個頂點;
(2)構造的最小生成樹有且僅有 n-1條邊;
(3)構造的最小生成樹中不存在迴路。
構造最小生成樹的方法有許多種,典型的方法有兩種,一種是普里姆(prim)演算法,一種是克魯斯卡爾(kruskal)演算法。
一普里姆(prim)演算法
假設 g=(v,e)為一無向連通網,其中,v 為網中頂點的集合,e 為網中邊的集合。設定兩個新的集合 u 和 t,其中,u 為 g 的最小生成樹的頂點的集合,t 為 g 的最小生成樹的邊的集合。普里姆演算法的思想是:令集合 u 的初值為 u=(假設構造最小生成樹時從頂點 u1開始) ,集合 t 的初值為 t={}。從所有的頂點 u∈u 和頂點 v∈v-u 的帶權邊中選出具有最小權值的邊(u,v) ,將頂點 v 加入集合 u 中,將邊(u,v)加入集合 t 中。如此不斷地重複直到 u=v 時,最小生成樹構造完畢。此時,集合 u 中存放著最小生成樹的所有頂點,集合 t中存放著最小生成樹的所有邊。
以下圖(a)為例,說明用普里姆演算法構造圖的無向連通網的最小生成樹的過程。
為了分析問題的方便,無向連通網如圖(a)所示。 初始時, 演算法的集合 u=, 集合 v-u=, 集合 t={},如圖(b)所示。在所有 u 為集合 u 中頂點、v 為集合 v-u 中頂點的邊(u,v)中尋找具有最小權值的邊,尋找到的邊是(a,d),權值為 20,把頂點 b 加入到集合u 中, 把邊(a,d)加入到集合 t 中, 如圖 (c)所示。 在所有 u為集合 u 中頂點、v 為集合 v-u 中頂點的邊(u,v)中尋找具有最小權值的邊, 尋找到的邊是(d,e), 權值為 10,把頂點 e 加入到集合 u 中,把邊(d,e)加入到集合 t 中,如圖(d)所示。隨後依次從集合 v-u 中加入到集合 u 中的頂點為 b、c,依次加入到集合t中的邊為(a,b)(權值為 60) 、(e,c) (權值為 70) ,分別如圖 (e)、(f)所示。最後得到的圖(f)所示就是原無向連通網的最小生成樹。
本書以無向網的鄰接矩陣類 netadjmatrix來實現普里姆演算法。netadjmatrix類的成員欄位與無向圖鄰接矩陣類 graphadjmatrix的成員字段一樣,不同的是,當兩個頂點間有邊相連線時,matirx 陣列中相應元素的值是邊的權值,而不是 1
無向網鄰接矩陣類 netadjmatrix源**的實現如下所示:
publicclass netadjmatrix: igraph//繼承與圖形的介面
//獲取索引為index的頂點的資訊 演算法的時間複雜度是o(1)
public nodegetnode(int
index)
//設定索引為index的頂點的資訊 演算法的時間複雜度是o(1)
public具體如圖所示:void setnode(int index, nodev)
//邊的數目屬性 可讀可寫的屬性
public
intnumedges
set }
//獲取matrix[index1, index2]的值 演算法的時間複雜度是o(1)
public
int getmatrix(int index1, int
index2)
//設定matrix[index1, index2]的值 演算法的複雜度是o(1)
public
void setmatrix(int index1, int index2, int
v)
//獲取頂點的數目 演算法的時間的複雜度是o(1)
public
intgetnumofvertex() //
獲取邊的數目 演算法的時間的複雜度是o(1)
public
intgetnumofedge()
//v是否是無向網的頂點
//如果包含這個頂點 返回為真,否則返回為假。
//由於這是一層迴圈,演算法的複雜度是o(n)
public
bool isnode(nodev)
} return
false
; }
//獲得頂點v在頂點陣列中的索引
// 如果相等,返回相應的索引。
//由於是一層迴圈,時間的複雜度是o(n)
public
int getindex(nodev)
} return
i; }
//在頂點v1、v2之間新增權值為v的邊
//新增相應的權值的v的邊, 這是乙個對稱矩陣。
public
void setedge(nodev1, nodev2, int
v)
//矩陣是對稱矩陣
matrix[getindex(v1), getindex(v2)] =v;
matrix[getindex(v2), getindex(v1)] =v;
++numedges;
} //刪除v1和v2之間的邊
// 刪除對稱矩陣。
public
void deledge(nodev1, nodev2)
//v1和v2之間存在邊
if (matrix[getindex(v1), getindex(v2)] != int
.maxvalue)
} //判斷v1和v2之間是否存在邊
//判斷相應 不是 最大值 返回為真 否則 為假 演算法的時間複雜度o(1)
public
bool isedge(nodev1, nodev2)
//v1和v2之間存在邊
if (matrix[getindex(v1), getindex(v2)] != int
.maxvalue)
else
//v1和v2之間不存在邊
} }
為實現普里姆演算法, 需要設定兩個輔助一維陣列 lowcost和 closevex, lowcost用來儲存集合 v-u 中各頂點與集合 u 中各頂點構成的邊中具有最小權值的邊的權值;closevex 用來儲存依附於該邊的在集合 u 中的頂點。假設初始狀態時,u=(u1為出發的頂點) ,這時有 lowcost[0]=0,它表示頂點 u1已加入集合 u中。陣列 lowcost 元素的值是頂點 u1 到其他頂點所構成的直接邊的權值。然後不斷選取權值最小的邊(ui,uk)(ui∈u,uk∈v-u),每選取一條邊,就將 lowcost[k]置為 0,表示頂點 uk 已加入集合 u 中。由於頂點 uk 從集合 v-u 進入集合 u 後,這兩個集合的內容發生了變化, 就需要依據具體情況更新陣列lowcost和closevex中部分元素的值。把普里姆演算法 primnetadjmatrix類的成員方法,實現的源**如下:
public具體實現,如圖所示:int prim()
//某個頂點加入集合u
lowcost[0] = 0
; closevex[
0] = 0
; //判斷最小的權值通過的頂點的迴圈就此開始
for(int i=0; ii)
++j;
} //新頂點加入集合u
lowcost[k] = 0;
//重新計算該頂點到其餘頂點的邊的權值
for (j = 1; j < nodes.length; ++j)
} }
return
closevex;
} //我們明顯的看出來,由於用到了雙重迴圈,其演算法的時間的複雜度是o(n^2)
在普里姆演算法中,第乙個for迴圈的執行次數為n-1,第二個for迴圈中又包括了乙個while迴圈和乙個for迴圈,執行次數為 2(n-1)2,所以普里姆演算法的時間複雜度為o(n2)。
這節,我們隊圖的引用做了乙個拋磚引玉的介紹,主要是普利姆演算法,解決 最小生成樹問題。下節,我們介紹一下克魯斯卡爾演算法解決最小生成樹的問題,和其他的應用。對圖做乙個總結等等。
C 資料結構與演算法揭秘14
好久,沒寫blog了,今天,多寫點。上節說到那裡了,是不是說圖的遍歷,這節,我們來通過圖的具體的應用了。首先,看看最小生成樹的應用了。什麼是最小生成樹了?由生成樹的定義可知,無向連通圖的生成樹不是唯一的,對連通圖的不同遍歷就得到不同的生成樹。圖 b 所示是圖 a 所示的無向連通圖的部分生成樹。所謂最...
資料結構與演算法 揭秘
字面意思就是研究資料的一種方法,就是研究資料在程式中組織的一種方法。資料結構就是,元素與元素有一種或者多種關係的集合,在軟體界有一種比較普片的公式就是程式 資料結構 演算法。1 集合 set 和數學的集合一樣,具有唯一性,確定性,無序性。2 線性結構 典型的資料庫二維表,一對一的關係。3 樹形結構 ...
C 資料結構與演算法揭秘一
這裡,我們 來說一說c 的資料結構了。什麼是資料結構。資料結構,字面意思就是研究資料的方法,就是研究資料如何在程式中組織的一種方法。資料結構就是相互之間存在一種或多種特定關係的資料元素的集合。程式界有一點很經典的話,程式設計 資料結構 演算法。用源 來體現,資料結構,就是程式設計。他有哪些具體的關係...