圖相關演算法的實現。一種不一樣的樹形結構
連線問題 connectivity problem
視覺化的來看連線問題:
連線問題
左上右下是否是連線的呢?
意義:實際應用中的作用
社交網路:facebook中使用者a和b中的聯絡(好友關係)。是否能聯絡到。
**電影書籍,多**之間形成網路。
網際網路網頁之間形成的網路
路由器和路由器之間形成的也是網路
道理交通,航班排程都是網路
數學中的集合類實現
並就是實現並集。& 查詢連線問題 & 路徑問題
比路徑問題要回答的問題少(路徑是什麼,連線問題只問有沒有連)
- 和二分查詢作比較:順序查詢法順便回答了rank。和前面其他元素的位置
- 和堆作比較:只關心最大最小。
除了回答問題本身之外是不是額外的回答了別的問題。很有可能就存在
更高效的演算法。:因為高效演算法不需要回答額外的問題。
對於一組資料,主要支援兩個動作:
- union( p , q )
- find( p )
用來回答乙個問題
- isconnected( p , q )
最簡單的表示方式;
陣列。0,1.
0-4 5-9
0-4是一組,5-9是一組。組內之間有聯絡
奇偶
奇數是一組,偶數是一組。
namespace uf1
~unionfind()
//傳入元素p,返回元素對應的id。
int find(int p)
bool isconnected(int p, int q)
//傳入兩個元素,並
void unionelements(int p, int q)
};}
testhelper.h:
namespace unionfindtesthelper
for(int i = 0 ; i < n ; i ++ )
time_t endtime = clock();
cout<<"uf1, "<<2*n<<" ops, "int main()
執行結果:
快速查詢,並很慢
quick find 查詢時只需要o(1)級別。但是並確很慢並查集的另一種實現思路
常規實現思路
將每乙個元素,看做是乙個節點。
元素節點
每個元素擁有乙個指向父節點的指標。然後最上面的父節點指標指向自己。
quick union
陣列存放父親
parent(i) = i;
初始狀態
union 3 4
union 3 4
union 3 8
union 3 8
union 6 5
union 6 5
union 9 4
union 9 4
要將9連線到4的根節點8上去。陣列中:4-3-8-8 8是4的根節點。9指向8.4和9連線在一起:因為根相同。
成果
其中6和2連線是6的根0和2的根1選取了1將0掛上。
namespace uf2
~unionfind()
//不斷向上找父親
int find(int p)
//看是否能找到同樣的根
bool isconnected( int p , int q )
//找到p的根,和q的根
void unionelements(int p, int q)
};}
執行結果:
執行結果
當n大的時候,方法1更優了。並查集的優化
問題:union 9,4 & union 4 9
union 9 4
9的元素少,將它指向4的根節點。形成的樹層數低。
// 我們的第三版union-find
namespace uf3
}// 析構函式
~unionfind()
// 查詢過程, 查詢元素p所對應的集合編號
// o(h)複雜度, h為樹的高度
int find(int p)
// 檢視元素p和元素q是否所屬乙個集合
// o(h)複雜度, h為樹的高度
bool isconnected( int p , int q )
// 合併元素p和元素q所屬的集合
// o(h)複雜度, h為樹的高度
void unionelements(int p, int q)
else}};
}
執行結果:
執行結果
優化相當明顯。
int main()
100萬在1秒之內
union 4 2
合併4和2
依靠集合的size來決定誰指向誰並不完全合理。根據層數才最合理基於rank的優化
namespace uf4
}// 析構函式
~unionfind()
// 查詢過程, 查詢元素p所對應的集合編號
// o(h)複雜度, h為樹的高度
int find(int p)
// 檢視元素p和元素q是否所屬乙個集合
// o(h)複雜度, h為樹的高度
bool isconnected( int p , int q )
// 合併元素p和元素q所屬的集合
// o(h)複雜度, h為樹的高度
void unionelements(int p, int q)
else if( rank[qroot] < rank[proot])
else}};
}
// 對於uf3來說, 其時間效能依然是o(n*h)的, h為並查集表達的樹的最大高度
// 但由於uf3能更高概率的保證樹的平衡, 所以效能更優
unionfindtesthelper::testuf3(n);
// uf4雖然相對uf3進行有了優化, 但優化的地方出現的情況較少,
// 所以效能更優表現的不明顯, 甚至在一些資料下效能會更差
unionfindtesthelper::testuf4(n);
執行結果
路徑壓縮(path compression)
前面我們都在優化union。其實find我們也可以進行優化。
1我們要find4
4去連線它爺爺
4去連線它爺爺。下面考查2.
2連線爺爺
路徑壓縮
int find(int p)
}
最優的情況
寫乙個遞迴的函式:呼叫findx,返回的就是x節點的根。讓每個parentx指向findx的結果。findx的結果也是findparentx的結果。找x的時候,將x的findparent的結果,指向父親的結果。**:
// path compression 2, 遞迴演算法
if( p != parent[p] )
parent[p] = find( parent[p] );
return parent[p];
優化情況並不明顯。甚至因為遞迴的消耗,。所以理論最優不一定實際好。
並查集的操作,時間複雜度近乎是o(1)的。
- 經過路徑壓縮:近乎1就能到根節點。
解決圖,網路連線。最短路徑。路徑是什麼?都得使用圖論。
資料結構與演算法之並查集
並查集結構可以用於 1 檢查兩個元素是否屬於同乙個集合 比如對於圖1這個例子來說,如果我們想要檢查節點d和節點e是否屬於同乙個集合,可以這樣操作 d節點往上找其父節點,一直往上找,直到某個節點的父節點是其本身,此時停止 找到了節點a e節點也按照相同的步驟往上找其父節點,找到節點a 如果這兩個節點往...
資料結構與演算法之並查集
並查集 union find 是一種高效的資料結構,主要的操作有 為方便敘述,把所有元素視作點,元素之間的關係視作線,存在聯絡便存在關係 需要注意的是,這裡的關係應當是1.自反的,2.對稱的,3.傳遞的 所謂合併,便是將兩個點之間 畫 一條線。又上邊的定義不難理解相連的若干點之間互相存在關係,這樣我...
演算法與資料結構 並查集 Disjoint Set
並查集 disjoint set 用來判斷已有的資料是否構成環。在構造圖的最小生成樹 minimum spanning tree 時,如果採用 kruskal 演算法,每次新增最短路徑前,需要先用並查集來判斷一下這個路徑是否會構成環。遍歷圖的每一條邊,按照下面的原則將對應的兩個頂點新增到集合中 為了...