フォーチュンは、達成するための基礎class5-トピック6互いに素セット義理を残しました

1.はじめに:互いに素セット

そして、調査の役割は、主に2つのセットがあります:
①簡単なチェックの二つの要素が同じセットされている
②2セットをマージします。

(1)互いに素なセット構造

コレクションがある要素のノードのセットを表し唯一の要素である場合には、要素の父は、自分です。
ここに画像を挿入説明
ノードは、それ自体を指す最上位ノードの集まり、上位ノードに対する下位ノードの父、父親よりも存在する場合、これは最上位のノードは、ノードの集合を表すと呼ばれます。5,4 3,3の父親として、図の父は、それ自身です。
ここに画像を挿入説明

(2)と原則セットをチェック

①検索:検索と仮定aを、bが、彼らは同じセット、同じセットの場合と同様に異なっていない場合のために、B、代表ノードをその代表ノードを見つけ、同じセットです。以下、2,5の同じセット、4,5-同じセット内にない
ここに画像を挿入説明
②合成
二組は同じ設定されていない場合には、より短い長さの代表ノードの父セットは代表ノードの長さを指します。

ここに画像を挿入説明

2.分析

クラスの(1)デザイン

その父親の要素を見つける最初fatherMapに対して実現2つの互いに素セット・マップを使用して、鍵は、そのファザーノードの現在のノード値を表します。SizeMapがその全長の第2のセットを記録するために使用される、キー値は、コレクションの長さであり、現在のノードを示しています。

class UnionFindSet 
{
private:
	hash_map<char,char> fatherMap;
	hash_map<char,int> sizeMap;
public:
	 UnionFindSet(vector<char> data);//构造
	 char findHead(char cur);		//找集合的代表节点
	 bool isameset(char a,char b);	//判断是否是同一个集合
	 void Union(char a,char b);		//合并集合
};

コンストラクタ

UnionFindSet::UnionFindSet(vector<char> data)
{
	{
		 fatherMap.clear();
		 sizeMap.clear();
		 //将vector的元素各自形成一个集合
		 for(auto var:data)
		 {
			 fatherMap.insert(pair<char,char>(var,var));//单个节点father指向自己
			 //sizeMap[var] = 1;
			 sizeMap.insert(pair<char,int>(var,1));//单个节点长度是1
		 }
	 }
}

(2)代表ノードを探します

特徴代表ノードは、自身の父親ノードは、全体的なアイデアはfatherMapが通じ段階的に代わって来たことによって、その父ノードへの現在のノードが同じノードであるです。

//递归版
char UnionFindSet::findHead(char cur)
{
	char father = fatherMap[cur];	//找到当前节点的father
	if(father != cur)				//father和当前节点不同表示当前节点不是代表节点,继续找
	{
		cur = father;
		father = findHead(cur);		//递归放入father继续找
	}
	fatherMap[cur] = father;		//递归后father是代表节点,对每个子节点father节点都改为代表节点
	return father;
}
//非递归版
char UnionFindSet::findHead(char cur)
{
	stack<char> child;
	while(fatherMap[cur] != cur)
	{
		child.push(cur);		//将沿途非代表节点入栈
		cur = fatherMap[cur];	//将当前节点father变为当前节点继续判断
	}
	//运行至此处时,cur是代表节点
	while(!child.empty())
	{
		fatherMap[child.top()] = cur;	//将栈中的非代表节点的father指向代表节点,完成扁平化
		child.pop();					//出栈
	}
	return cur;
}

(3)同じセットかどうかを決定します

bool UnionFindSet::isameset(char a,char b)
{
	return findHead(a) == findHead(b);
}

(4)二組合わせ

二つの異なる代表ノードは、ノードの偶数比較長セットが短いの長いセットに収集ポイントを表す場合には、2つのセットの合計長さは、代表的なノードに適用されます。
注:唯一のノードの全長を表し比較する比較し、非プライマリノード、の長さのは意味がありません。

void UnionFindSet::Union(char a,char b)
{
	//找出两个集合的代表节点
	char head1 = findHead(a);
	char head2 = findHead(b);

	if(head1 == NULL || head2 == NULL)//边界问题,空集合直接返回
		return;

	if(head1!=head2)				//不在同一集合时合并
	{
		//记录两个代表节点的长度
		int size1 = sizeMap[head1];
		int size2 = sizeMap[head2];
		//将短的接入长的中
		if(size1 <= size2)
		{
			fatherMap[head1] = head2;
			sizeMap[head2] = size1 + size2;
		}
		else
		{
			fatherMap[head2] = head1;
			sizeMap[head1] = size1 + size2;
		}
	}
}

3.完全なコード

#include<iostream>
#include<hash_map>
#include<vector>
#include<stack>
using namespace std;

class UnionFindSet 
{
private:
	hash_map<char,char> fatherMap;
	hash_map<char,int> sizeMap;
public:
	 UnionFindSet(vector<char> data);//构造
	 char findHead(char cur);		//找集合的代表节点
	 bool isameset(char a,char b);	//判断是否是同一个集合
	 void Union(char a,char b);		//合并集合
};

UnionFindSet::UnionFindSet(vector<char> data)
{
	{
		 fatherMap.clear();
		 sizeMap.clear();
		 //将vector的元素各自形成一个集合
		 for(auto var:data)
		 {
			 fatherMap.insert(pair<char,char>(var,var));//单个father指向自己
			 //sizeMap[var] = 1;
			 sizeMap.insert(pair<char,int>(var,1));//单个长度是1
		 }
	 }
}
//递归版
//char UnionFindSet::findHead(char cur)
//{
//	char father = fatherMap[cur];	//找到当前节点的father
//	if(father != cur)				//father和当前节点不同表示当前节点不是代表节点,继续找
//	{
//		cur = father;
//		father = findHead(cur);		//递归放入father继续找
//	}
//	fatherMap[cur] = father;		//递归后father是代表节点,对每个子节点father节点都改为代表节点
//	return father;
//}


//非递归版
char UnionFindSet::findHead(char cur)
{
	stack<char> child;
	while(fatherMap[cur] != cur)
	{
		child.push(cur);		//将沿途非代表节点入栈
		cur = fatherMap[cur];	//将当前节点father变为当前节点继续判断
	}
	//运行至此处时,cur是代表节点
	while(!child.empty())
	{
		fatherMap[child.top()] = cur;	//将栈中的非代表节点的father指向代表节点,完成扁平化
		child.pop();					//出栈
	}
	return cur;
}

bool UnionFindSet::isameset(char a,char b)
{
	return findHead(a) == findHead(b);
}

void UnionFindSet::Union(char a,char b)
{
	//找出两个集合的代表节点
	char head1 = findHead(a);
	char head2 = findHead(b);

	if(head1 == NULL || head2 == NULL)//边界问题,空集合直接返回
		return;

	if(head1!=head2)				//不在同一集合时合并
	{
		//记录两个代表节点的长度
		int size1 = sizeMap[head1];
		int size2 = sizeMap[head2];
		//将短的接入长的中
		if(size1 <= size2)
		{
			fatherMap[head1] = head2;
			sizeMap[head2] = size1 + size2;
		}
		else
		{
			fatherMap[head2] = head1;
			sizeMap[head1] = size1 + size2;
		}
	}
}
int main()
{
	vector<char> temp;//={'A','B','C','D','E,'F'};
	temp.push_back('A');
	temp.push_back('B');
	temp.push_back('C');
	temp.push_back('D');
	temp.push_back('E');
	temp.push_back('F');
	temp.push_back('G');
	temp.push_back('H');
	UnionFindSet m(temp);
	m.Union('B','A');
	
	m.Union('C','B');

	m.Union('D','E');
	m.Union('B','D');
	system("pause");
	return 0;
}

4.ファイル名を指定して実行結果

セットB及びセットDは、Aの下に示した結果を合わせ、B、C、Eは、Eを指すようにA、D点に
ここに画像を挿入説明
ここに画像を挿入説明

公開された51元の記事 ウォンの賞賛1 ビュー1368

おすすめ

転載: blog.csdn.net/shi_xiao_xuan/article/details/104144598