算法筆記---並查集

並查集是一種維護集合的數據結構,它的名字中“並”“查”“集”分別取自Union(合併)、Find(查找)、Set(集合)這3個單詞。也就是說,並查集支持下面兩個操作:

①合併:合併兩個集合。
②查找:判斷兩個元素是否在一個集合。

那麼並查集是用什麼實現的呢?
其實就是用一個數組:

int father[N]

其中fahter[i]表示元素i的父親結點,而父親結點本身也是這個集合內的元素(1≤i≤N)。例如father[1]=2就表示元素1的父親結點是元素2,以這種父系關係來表示元素所屬的集合。另外,如果father[i]=i,則說明元素i是該集合的根結點,但對同一個集合來說只存在一個根結點,且將其作爲所屬集合的標識。

#include<iostream>
using namespace std;

const int max_union_find_set = 1001;
int father[max_union_find_set] = { 0 };

//初始化
void init(int father[]) {
	for (int i = 1;i <= max_union_find_set;i++)
	{
		father[i] = i;
	}
}

//查找(遞歸)
int find_father(int x) {
	if (father[x] == x)
	{
		return x;
	}
	else
	{
		return find_father(father[x]);
	}
}

//合併
void union_father(int a, int b) {
	int father_a = find_father(a);
	int father_b = find_father(b);
	if (father_a != father_b)//如果不在一個集合,則合併
	{
		father[father_a] = father_b;
	}
}

int main() {

	
	system("pause");
	return 0;
}

在合併的過程中,只對兩個不同的集合進行合併,如果兩個元素在相同的集合中,那麼就不會對它們進行操作。這就保證了在同一個集合中一定不會產生環,即並查集產生的每一個集合都是一棵樹。

上面講解的並查集查找函數是沒有經過優化的,在極端情況下效率較低。現在來考慮一種情況,即題目給出的元素數量很多並且形成一條鏈,那麼這個查找函數的效率就會非常低。

下面給出解決方案:路徑優化
這相當於把查找結點的路徑上的所有結點的父親都指向根結點
則查找的複雜度可以變爲O(1)。

int find_father(int x) {
	if (father[x] == x)
	{
		return x;
	}
	else
	{
		int root_val = find_father_2(father[x]);
		father[x] = root_val;//將根結點賦值給father[x]
		return root_val;//返回根結點
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章