左神讲的并查集算法的C++实现版本,少了一个步骤,没有检查传入结点是否是集合中的元素。
#include<iostream>
#include <vector>
#include<unordered_map>
using namespace std;
template <class T>
class UnionSet
{
private:
unordered_map<T, T> parents;
unordered_map<T, int> sizeMap;
public:
UnionSet(vector<T> v)
{
// 初始化每一个元素的根节点都为自身, 初始化每一个集合的大小为1
for (auto i : v)
{
parents[i] = i;
sizeMap[i] = 1;
}
}
// 优化,将查找路径上的所有结点都直接连到根节点下面,方便下次查询(一步查到)
// 优化思路:使得查找路径尽可能短
T findFather(T x)
{
// 用一个vector记录查找路径上的中间结点
vector<T> temp;
while (x != parents[x])
{
temp.push_back(x);
x = parents[x];
}
// 将中间结点的parent都修改为根结点
for (auto i : temp) parents[i] = x;
return x;
}
void unionElements(T x1, T x2)
{
// step1: 先找到两个结点的根节点
T aHead = findFather(x1);
T bHead = findFather(x2);
// step2: 将结点数量小的集合连到结点数量多的集合的下面
T minHead = sizeMap[aHead] <= sizeMap[bHead] ? aHead : bHead;
T maxHead = minHead == aHead ? bHead : aHead;
parents[minHead] = maxHead;
// step3: 修改相应的sizeMap
sizeMap[maxHead] += sizeMap[minHead];
sizeMap.erase(minHead);
}
// 判断两个元素是否属于同一个集合
bool isSameset(T x1, T x2)
{
return findFather(x1) == findFather(x2);
}
void printSet()
{
cout << "values in parents:" << endl;
for (auto i : parents) cout << i.first << " " << i.second << endl;
cout << endl;
cout << "values in sizeMap:" << endl;
for (auto i : sizeMap) cout << i.first << " " << i.second << endl;
}
};
int main()
{
vector<int> vec = { 1,2,3,4,5,6,7 };
UnionSet<int> uset(vec);
cout << uset.isSameset(1, 2);
cout << endl;
uset.unionElements(1, 3);
uset.unionElements(1, 5);
uset.unionElements(7, 5);
uset.printSet();
cout << uset.isSameset(3, 5);
}