by:
潘雲登
對於商業目的下對本文的任何行為需經作者同意。
寫在前面
1.本文內容對應《演算法導論》(第
2版)》第
23章。 2.
主要介紹了兩種構建最小生成樹的方法:
kruskal
演算法和prim
演算法。 3.
kruskal
演算法和prim
演算法,可以以鄰接表表示的圖為基礎(可參考《
圖的表示與搜尋
》),並且都利用了
貪心演算法
的思想。假設最小生成樹(
mst,
minimum spanning tree
)問題針對的是無向連通加權圖
g=(v, e)
,那麼mst
中邊的個數為
|v|-1
。kruskal
演算法
首先定義幾個概念。無向圖
g=(v, e)
的乙個割
(s, v-s)是對v
的乙個劃分。當一條邊
(u, v)∈e
的乙個端點屬於
s,而另乙個端點屬於
v-s時,稱邊
(u, v)
通過割(s, v-s)
。如果乙個邊的集合
a中沒有邊通過某一割,則說該割不妨礙邊集
a。如果某條邊的權值是通過乙個割的所有邊中最小的,則稱該邊為通過這個割的一條輕邊。
kruskal
演算法首先選擇權值最小的一條邊,並將它的兩個端點劃入
s,表示最小生成樹的乙個子集。然後,選擇通過割
(s, v-s)
的一條輕邊,將屬於
v-s的端點劃入
s。重複上述過程,直到集合
v-s為空。所有被選擇的邊即為最小生成樹的邊。
void mst_kruskal(adjlist *graphic)
}graphic->mst_size = j;
}其中,
make_set
執行時間為
o(1)
,對各條邊按權值進行的快速排序需要
o(e lg e)
,執行o(e)
次find_set
和union_set
操作所需的總時間為
o(e lg e)
。因此,
kruskal
演算法的總執行時間為
o(e lg e)。
這裡,用到了不相交集合上的操作(第
21章)。其中,
make_set(x)
建立乙個新的集合,其唯一成員為x。
union_set(x, y)
將包含x和y
的動態集合合併為乙個新的集合。
find_set(x)
返回乙個指標,指向包含
x的集合的代表。在不相交集合的一種實現中,用有根樹表示集合。每個結點僅指向其父結點。每棵樹的根作為集合的代表,並且是它自己的父結點。為改進執行時間,可採用兩種啟發式策略:一是按秩合併,其思想是把包含較少結點的樹的根指向包含較多結點的樹的根;二是路徑壓縮,使查詢路徑上的每個結點都直接指向根結點,但不改變結點的秩。為執行路徑壓縮,
find_set
是一種兩趟方法:一趟是沿查詢路徑上公升,直到找到根;一趟是沿查詢路徑下降,以便更新每個結點,使之直接指向根。
void make_set(dobj *obj)
void union_set(dobj *x, dobj *y)
void link_set(dobj *x, dobj *y)
else
}dobj * find_set(dobj *x)
prim
演算法
prim
演算法的特點是最小生成樹子集
a中的邊總是形成單棵樹。樹從任意根頂點開始形成,並逐漸生成,直至該樹覆蓋了
v中的所有頂點。在每一步,總是在以
a中頂點為乙個端點的所有邊中,選擇一條輕邊加入到樹中。在演算法的執行過程中,不在樹中的所有頂點都放在乙個基於邊權重的最小優先佇列中(可參考《
堆的使用
》)。
void mst_prim(adjlist *graphic, int start)
h.array[start].key = 0;
build_min_heap(&h);
graphic->mst_size = 0;
while(h.heap_size>0)
temp_lnode = graphic->vlist[temp_vhnode->index].link;
while(temp_lnode != null)
temp_lnode = temp_lnode->next;}}
free_heap(&h);
}這裡,暫且用
color
域標識頂點是否在優先佇列中。
prim
演算法的效能取決於優先佇列如何實現。如果用最小堆來實現,那麼
while
迴圈中,執行
|v|次的
heap_extract_min
操作需要
o(v lg v)
時間。另外,需要檢查
o(e)
條邊,而對邊進行
heap_decrease_key
操作需要
o(lg v)
時間。因此,
prim
演算法的整個執行時間為
o(v lg v+ e lg v)=o(e lg v)。
附最小堆實現的最小優先佇列。
typedef struct vertex_heap_node
vhnode;
typedef struct heap_array
heap;
int parent(int i)
; int left(int i)
; int right(int i)
; void exchange(vhnode *a, vhnode *b);
void init_heap(heap *h, int vertex_number);
void free_heap(heap *h);
void min_heapify(heap *h, int i)
}void build_min_heap(heap *h)
vhnode * heap_extract_min(heap *h)
void heap_decrease_key(heap *h, int i, int key)
}
演算法導論 最小生成樹
華電北風吹 日期 2016 1 16 常用的最小生成樹演算法有prime演算法和kruskal演算法。prime演算法基於節點,kruskal基於邊。1 prime演算法 prime演算法屬於貪心演算法,與廣度優先搜尋類似。保持乙個屬於已發現的最小生成樹節點的集合。每一次從未在樹中的節點中選擇乙個與...
演算法導論 最小生成樹擴充套件
一,次最小生成樹 定義 設t是圖g的最小生成樹,如果t1滿足 t1 min,則t1是g的次小生成樹。解釋 除了最小生成樹外,另外乙個生成樹的權值和最小的生成樹,定義為次最小生成樹。經典題目 poj1679 the unique mst,對於一張圖,判斷最小生成樹是否惟一。惟一的定義是 不存在第二棵生...
演算法導論 最小生成樹(prim演算法)
一,定義 沒有權值時 乙個有n個節點的聯通圖,生成樹是,極小聯通子圖。包含圖中所有節點,且有保持圖聯通的最少的邊。邊有權值時 無向聯通圖g v,e 權值函式,w e r。找到g的一棵最小生成樹,使得 w t 最小。w t 為最小生成樹所有邊權值和。二,prime演算法 1 初始化 u te 節點集u...