注意,不同教材在介紹森林的遍歷方法時會有不同的表述,有些教材會將後序遍歷稱為中序遍歷,但實質上遍歷方法是一樣的。
森林的先序遍歷的規則:
訪問森林中第一棵樹的根結點
先序遍歷森林中第一棵樹的子樹森林
先序遍歷森林中,除第一棵樹外其餘樹構成的森林
森林的後序遍歷的規則:
後序遍歷森林中第一棵樹的根結點的各子樹所構成的森林
訪問森林中第一棵樹的根結點
後序遍歷森林中除第一棵樹外其餘樹構成的森林
二叉樹是樹的特例,而樹也可以看作森林的特例。在接下來的課程中,會學習一種用森林來表示的高效資料結構——並查集,包括初始化、查詢和合併操作,以及兩種非常有效的優化。
在電腦科學中,並查集(merge-find set),也被稱為不相交集合(disjoint set),是用於解決若干的不相交集合的如下幾種操作的統稱:
make-set(x):即初始化操作,建立乙個只包含元素 x 的集合。
union(x, y):即合併操作,將包含 x 和 y 的集合合併為乙個新的集合。
find-set(x):即查詢操作,計算 x 所在的集合。
並查集通常同時指代不相交集合的資料結構及其對應的演算法,其在有些教材中的英文名稱也叫做 disjoint set union,表示用於求不相交集合並集的相關演算法。
通常我們會用有根樹來表示集合,樹中的每乙個結點都對應集合的乙個成員,每棵樹表示乙個集合。
每個成員都有一條指向父結點的邊,整個有根樹通過這些指向父結點的邊來維護。每棵樹的根就是這個集合的代表,並且這個代表的父結點是它自己。
通過這樣的表示方法,我們將不相交的集合轉化為乙個森林,也叫不相交森林。接下來會介紹,如何通過不相交森林實現並查集的初始化、合併和查詢操作。
通常並查集初始化操作是對每個元素都建立乙個只包含該元素的集合。這意味著每個成員都是自身所在集合的代表,所以我們只需要將所有成員的父結點設為它自己就好了。
在不相交森林中,並查集的查詢操作,指的是查詢出指定元素所在有根樹的根結點是誰。我們可以通過每個指向父結點的邊回溯到結點所在有根樹的根,也就是對應集合的代表元素。
並查集的合併操作需要用到查詢操作的結果。合併兩個元素所在的集合,需要首先求出兩個元素所在集合的代表元素,也就是結點所在有根樹的根結點。接下來將其中乙個根結點的父親設定為另乙個根結點。這樣我們就把兩棵有根樹合併成一棵了。
並查集的查詢操作最壞情況下的時間複雜度為 o(n)o(n),其中 n 為總元素個數。最壞情況發生時,每次合併對應到森林上都是乙個點連到一條鏈的一端。此時如果每次都查詢鏈的最底端,也就是最遠離根的位置的元素時,複雜度便是 o(n)o(n) 了。
為了改善時間效率,可以通過啟發式合併方法,將包含較少結點的樹接到包含較多結點的樹根上,可以防止樹退化成一條鏈。另外,我們也可以通過路徑壓縮的方法來進一步減少均攤複雜度。同時使用這兩種優化方法,可以將每次操作的時間複雜度優化至接近常數級。
含秩優化
#include
using
namespace
std;
class disjointset
}~disjointset()
int find_set(int node)
return node;
}bool merge(int node1, int node2)
father[ancestor1] = ancestor2;
rank[ancestor2]=max(rank[ancestor1]+1,rank[ancestor2]);
return
true;
}return
false;
}};int main() else
}return
0;}
含路徑優化
#include
using
namespace
std;
class disjointset
}~disjointset()
int find_set(int node)
return father[node];
}bool merge(int node1, int node2)
father[ancestor1] = ancestor2;
rank[ancestor2] = max(rank[ancestor1] + 1, rank[ancestor2]);
return
true;
}return
false;
}};int main() else
}return
0;}
並查集判斷環 並查集的路徑壓縮 和 帶秩優化
1.判斷環 參考部落格 思路 1.將用過的路徑連起來成為乙個集合,記錄下來 2.如果連通的兩個邊屬於乙個集合,那麼這個並查集就形成了乙個環 燈神 如果刪除2,4邊 可將2,4這條邊刪除測試 是否正確 如果刪除此邊則不會出現環記得將6改為5 initialise parent for int i 0 ...
並查集模板 (路徑壓縮 秩的合併)優化
void init int findroot int x return findroot pre x 否則一直往上找,找其最頂層的根結點 遞迴方式 int findroot int x return pre x findroot pre x 否則一直往上找,找其最頂層的根結點,並將路徑上的關聯點都加...
並查集 按秩合併 路徑壓縮
一種可以動態維護若干個不重疊的集合或無向圖的連通塊的資料結構。主要支援以下操作 find 查詢乙個元素屬於哪個集合 merge 合併兩個集合 並查集的每個集合都需要乙個 爹 來表示這整個集合,所以判斷兩個元素是否在同一集合,就看他們爹是否相同。有乙個顯而易見的初始化,對於要維護的序列,初始每個元素的...