并查集
概念
并查集本身是一种树型的数据结构,是描述集合的利器,用于处理一些不相交集合(disjoint sets)的合并及查询问题。
下图是对并查集的直观描述,也基本展现了并查集的一些特性:
基本操作
初始化
把每个点所在集合初始化为其自身。
通常来说,这个步骤在每次使用该数据结构时只需要执行一次,无论何种实现方式,时间复杂度均为O(n)
查找
查找元素所在的集合,即根节点。
合并
将两个元素所在的集合合并为一个集合。
通常来说,合并之前,应先判断两个元素是否属于同一集合,这可用上面的“查找”操作实现。
代码
#include <iostream> #include <unordered_map> #include <vector> using namespace std; class UnionFind { private: unordered_map<char,char> ancestor_; // 用来存储祖先的 unordered_map<char, size_t> size_; // 用来存储每一个集合的大小的 public: //并查集初始化 UnionFind(const vector<char>& vec) { for(auto c:vec) { ancestor_.insert({c,c}); size_.insert({c,1}); } } // 查找元素属于哪一个集合 char Find(char c) { //这里假设传入的字符C都是集合中已经存在的值 char ancestor = ' '; char findc = c; while(ancestor!= findc) { ancestor = findc; findc = ancestor_[ancestor]; } //这里可以做一个优化,把这个树化扁平,以减少未来的查找时间复杂度 ancestor_[c] = ancestor; return ancestor; } void Union(char u1, char u2) { // 找到他们的祖先 char anc1 = Find(u1); char anc2 = Find(u2); // 如果祖先相同就不做任何事情 if (anc1 == anc2) return ; // 判断谁的size 大 && 若u1 size == u2 size,将u2挂在u1上 char maxu = size_[anc1] >= size_[anc2] ? anc1:anc2; char minu = maxu == anc1? anc2:anc1; ancestor_[minu] = maxu; } }; int main() { UnionFind a = UnionFind({'a','b','c','d','e','f','g'}); a.Union('a','b'); cout<<"b 的祖先是 :"<<a.Find('b'); return 0; }