A.ディスジョイント・セットが行うために使用することができます
図の連結成分の数を求めます。
II。基本的な操作をディスジョイントセット
互いに素なセットは、クエリに使用されるセット内の要素かどうか +のマージ2つの互いに素の集合。
彼は単純に2元の操作、これら二つの操作の操作に基づく誘導体は、持っています
- 二つの要素が集中してチェックしているの比較 - チェックし、2つの要素を比較すると、代表者の同じセットです
- 別の互いに素セットとしての要素、および、ターゲット・セットとセットの操作をするために - と集中要素にチェックを追加します。
三互いに素セットの最適化 - パス圧縮アルゴリズム
私たちは、BST、複雑さとその関連性の高い時間バイナリーツリーが探しを知ることを学ぶとき。線形二分木場合、検索時間の複雑要素はO(N)です。チェックフォーカスでは、あまりにも、私たちは木の高さを削減する方法を見つける必要があります。
もう一つ注意すべきは、実際の互いに素セットで無向グラフに対応することで、実際より一本の木よりもですが、それは我々のプログラムのために良いです。
ルート最適化アルゴリズムは、私たちの木の高さを低減するために使用される、それは我々の2つの互いに素セットの出発の動作から主に次のとおりです。
・Query要素
私たちは道の要素を照会すると、問い合わせについて枝の再建を、パス上のすべてのノードが直接ルートノードに接続されています。下の図:
・組み合わせたコレクション
TBTの下にマウントするように我々は(実際には、これは全く逆のアプローチである)左のサブツリーのルートに木のように、一番右のノードにはできません
私たちは、他に直接取り付け互いに素-セットにその多木の性質を利用し、ルートセットに確認する必要があります。
私たちはより良いと思います、我々は高さ変化を持っていないのでことを、小さな木の高さは大きな木の高さにマウント置きます。
もちろん、同じ高さの2つのツリーの高さは、それ+1作る場合。
(図2、図のシーイング下)
IV。テンプレート
実際には、これは書き込みの良いテンプレートではありません(変数の命名を参照してください。
しかし、私は限りだと思う十分であるそれらの考えを理解することができますテンプレートを読んだ後、数回書かれて。
// 像union set这种数据结构真的不适合使用成员方法来实现
// 还是像链表一样老老实实地用非成员方法来做好了
// 发现还是使用数组比较方便
constexpr int kNum = 100000;
int parent_[kNum]; // 记录每一个节点的父亲节点编号
int rank_[kNum]; // 用bits/stdc++.h还不能使用rank,不然会重名发生ambigous错误
void Initialize() {
// 初始化
for (int i = 0; i < kNum; ++i) {
parent_[i] = i;
rank_[i] = i;
}
}
int Find(int x) {
// 找到相应并查集的根节点
// 根节点的特征
if (x == parent_[x]) {
return x;
}
return parent_[x] = Find(parent_[x]); // 继续查找+路径压缩
}
void Union(int x, int y) {
int parent_x = Find(x);
int parent_y = Find(y);
// 如果在同一个并查集内
if (parent_x == parent_y) {
return;
}
// 如果不在一个并查集内, 根据rank来合并并查集
// 注意对rank的更新
if (rank_[parent_x] > rank_[parent_y]) {
parent_[parent_y] = parent_x; // y挂到x上
} else {
if (rank_[parent_x] == rank_[parent_y]) {
++rank_[parent_y]; // 由于接下来要挂到y上
}
parent_[parent_x] = parent_y; // x挂到y上
}