数据结构:集合

集合,数学中默认指无序集,用于表达元素的聚合关系。两个元素只有属于同一个集合与不属于同一集合两种关系。

常见实现方式: • std::unordered_set、std::unordered_map • 并查集、哈希表 • 启发式可并堆 并查集:如 亲戚

模板:

// 一定不要忘了初始化,每个元素单独属于一个集合
void init() {
for (int i = 1; i <= n; i++)
f[i] = i;
}
int find(int x) { // 查询集合的“代表”
if (x == fa[x])return x;
return fa[x] = find(fa[x]); // 顺便【路径压缩】
}
void join(int c1, int c2) { // 合并两个集合
// f1为c1的代表,f2为c2的代表
int f1 = find(c1), f2 = find(c2);
if (f1 != f2) {
if (size[f1] < size[f2]) // 【取较大者】作为代表
swap(f1, f2);
fa[f2] = f1;
size[f1] += size[f2]; // 只有“代表”的size是有效的
}}

Hash表

易知,就不过多说明了。

理论表明,并不是任意选择 Hash 函数都能取得同样的效果。 1. 使用较大的质数作为模数 模数越大,空间越多,越难以冲突。 同时,由于质数除了1和自身外没有其他因子,包含乘除运算 的 Hash 函数不会因为有公因子而导致不必要的 Hash 冲突。 2. 使用复杂的 Hash 函数 直接取模是最简单的方式。但复杂的 Hash 函数可使值域分布更均匀,降低冲突的可能。请注意Hash函数的输入应只与对象本身有关,而与随机数等任何 外界环境无关。

折叠之后,不同的数可能映射到同一个区域, 这一现象称为 Hash 冲突

数据结构:集合_第1张图片

三种解决方法: 1. 使用稳健的 Hash 函数,效率最高,冲突率最高 2. 使用十字链表,完全解决冲突,效率较低 3. 使用 Multi-Hash,折中的方法

你可能感兴趣的:(c++,数据结构)