互いに素-セットを持つファイル
1、互いに素セットのコンセプト
次のように権威ある解釈Baiduのウィキペディアによると、ばらばらのセットの定義は、おそらく次のとおりです。
ディスジョイントセット、問題の数のアプリケーションのセットは、N個の要素を持って、我々は通常、コレクションの各要素の先頭に作る単一の要素を構成し、その後、一定の順序がする時に、どこセットに属し、同じグループの要素をマージします繰り返される要素でコレクションを検索します。近年に特徴があるインフォマティクスにおける国内および国際的な競争の中でテーマを繰り返し、この種の問題は、複雑ないないようですが、しばしば空間で、それを記述するためにあなたの通常のデータ構造が大きすぎる場合は、データの量は、素晴らしいです、コンピュータは余裕がありません。でも、かろうじて合格の空間に、操作の時間計算量も非常に高く、単純な質問の結果が規定時間(1〜3秒)以内にゲームを実行する必要は計算できない、とだけチェックに使用することができます記述するために設定します。
素集合データ構造を合わせて問い合わせいくつかの互いに素なセット(互いに素なセット)を処理するための木です。多くの場合、表現するために森に使用します。
2、互いに素セットのリンクを持つファイル
(1)複合モード
文書は、実際には、あなたが表現するために、ツリー構造を使用することができます - ツリー構造といえば、コンピュータは同じよく知られたものを持っています。
あなたはこのコースでは、デザインモードに行けば、GOFは一般的にはデザインパターンの23種類を使用し、構造モデルのカテゴリに複合モードに関するファイルである話古典的な例が存在します。
複合モードが何であるか、のは、その定義を見てみましょう:
ユーザは、単一のオブジェクトとオブジェクトの組み合わせの一貫した組み合わせパターンを有するように、階層 - ツリー構造のオブジェクトを結合する「全部」を表すために、モードを組み合わせます。
まだ見つかって、これもで定義されたツリー構造のキーワードの!それが拡大しており、それは、その組合せモードと言われている単一のオブジェクトとオブジェクトの組み合わせを有する使用一貫性。
ここで、「一貫性」はそれを意味し、我々は類推を見たいことが何フォルダ例えば、下の画像では、私がボスという名前のデスクトップ上にフォルダを作成し、
私達はちょうどこのフォルダから今ありますそれを見て、それがとして見ることができる単一のオブジェクト、これは何も持っていなかった、作成したばかりの私のフォルダであるため、。
次に、Iボス再びフォルダにして、ボスという名前のフォルダを作成します。
今、私たちが見てサブフォルダのボスは、ボスのフォルダに存在するため、ボスは、もはや単一のオブジェクトであるボスとして見られるべきですそれは、あるオブジェクトの組み合わせ、およびサブフォルダのボスは、先ほど作成したということです、何も内部を得たので、あると考えることが原因である単一のオブジェクト。
現状はこのようです:
シングルオブジェクト- 「ボスフォルダ
のグループ化は、オブジェクト- 」ボスフォルダ
今、私たちは、この文を見て、「コンバインモードが可能に個々のオブジェクトとオブジェクトの組み合わせが持っている使用の一貫性を、」今ここで我々は、単一のオブジェクトがフォルダで、フォルダがオブジェクトの組み合わせである彼らが使用するので、明らかに、あります、持っているのと同じ方法、いわゆる一貫性を。
(2)フォルダの問い合わせ
クエリフォルダの場合は、確かに我々はそれに慣れていませんか?
クエリは、頻繁に使用されるフォルダー再帰クエリの方法を。
比如现在我桌面上有一个文件夹1,文件夹1里有文件夹2,文件夹2里有文件夹3,文件夹3里有文件夹4,文件夹4里有文件夹5,因而针对文件夹5所在位置的相对路径是1->2->3->4
我如果想找到文件夹5,我就得依次打开文件夹1、文件夹2、文件夹3、文件夹4,才能找到文件夹5。
(3)文件夹合并
对于文件夹的合并,也非常好理解,比如我现在桌面上有Boss和1两个文件夹。
很明显,Boss有老大的意思,因而即使1的手下人多,Boss也不在怕的,因而1乖乖地臣服于了Boss,变成了Boss的小弟…
于是我直接把文件夹1丢进了Boss文件夹里
因而Boss文件夹最终便变成了以下的结构:
整体结构示意图为:
Boss → boss
↓
1→2→3→4→5
3、并查集算法源码
(1)初始化
假设现在有n个文件夹,我们用一个数组f表示下标为i的文件夹的根文件夹,初始时每个文件夹的根文件夹为其自身
void initializeFolder(){
for(int i = 1; i <= n; i++)
f[i] = i;//每个文件夹的根文件夹为其自身
}
(2)查询
若我们需要查询文件夹x的根文件夹时:
int find(int x){
if(f[x] == x) return x;//如果x的根文件夹就是其自身
return find(f[x]); //否者递归查询找到x的根文件夹
}
(3)合并
当我们想把文件夹x所在的整个文件夹和y所在的整个文件夹合并时,我们需要需要先找到x的根文件夹a,再找到y的根文件夹b,再令a的根文件夹为b或令b的根文件夹为a即可。
void join(int x,int y){
int a = find(x);//找到x的根文件夹a
int b = find(y);//找到y的根文件夹b
if(a != b)//如果它们两不是同一个文件夹
f[a] = b;//令a的根文件夹为b
}
(4)路径压缩
(2)時間ステップのクエリは、問題がある:私たちは、時間後に戻って次の時間チェックを来るときのxフォルダ、我々はルート・ファイル・フォルダのケースを見つけるたびに、このクエリはそう、記録されません、以下のように複雑な操作は、繰り返されなければならない:
5つのボスルートフォルダのファイルを見つけるために私たち最初のフォルダ、我々は親フォルダの4-> 3 - > 2 - > 1 - >見つけるために有効にする必要がボスを、 ボス5のためのルート・ファイル・フォルダの最初の直接の原因の後に一度だけでなく、このような複雑な操作を見つけるために、次回を避けるために、我々は見つけることができるようになります
Zhefan操作後、次の時間が、我々は、ルート・ファイル・フォルダーに来て5クリップは、それが一度だけチェックされている場合、十分です。
int find(int x){
if(f[x] == x) return x;//如果x的根文件夹就是其自身
f[x] = find(f[x]);//递归查询找到x的根文件夹,并更新f[x]
return f[x];
}
(5)試験
#include<iostream>
using namespace std;
const int N = 5;
int f[N+1];
void initializeFolder(){
for(int i = 1; i <= N; i++)
f[i] = i;
}
int find(int x){
if(f[x] == x) return x;//如果x的根文件夹就是其自身
f[x] = find(f[x]);//递归查询找到x的根文件夹
return f[x];
}
void join(int x,int y){
int a = find(x);//找到x的根文件夹a
int b = find(y);//找到y的根文件夹b
if(a != b)//如果它们两不是同一个文件夹
f[a] = b;//令a的根文件夹为b
}
int main(){
initializeFolder();//文件夹初始化
join(1,2);//令文件夹1的根文件夹为2
join(1,3);//令文件夹1的根文件夹为3,即让文件夹2的根文件夹为3
join(2,3);//令文件夹2的根文件夹为3
join(3,4);//令文件夹3的根文件夹为4
join(4,5);//令文件夹4的根文件夹为5
//此时文件夹的目录级为5->4->3->2->1
cout << find(1) << endl;
cout << find(2) << endl;
cout << find(3) << endl;
cout << find(4) << endl;
cout << find(5) << endl;
}
結果: