C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ unordered_set哈希集合

C++中unordered_set哈希集合的实现

作者:MzKyle

std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unordered_set的使用,感兴趣的可以了解一下

一、概述

std::unordered_set 是 C++ 标准库(C++11 引入)中的无序容器,用于存储唯一的元素(无重复值),底层基于哈希表(哈希桶) 实现。与 std::set(基于红黑树,元素有序)相比,它的核心特点是:

二、头文件与命名空间

使用 std::unordered_set 需包含头文件 <unordered_set>,并位于 std 命名空间中:

#include <unordered_set>
using namespace std; // 或显式使用 std::unordered_set

三、常用方法与示例

1. 构造与析构

std::unordered_set 提供多种构造方式,满足不同初始化需求:

方法说明
unordered_set()默认构造:创建空容器
unordered_set(initializer_list<T> init)初始化列表构造:用 {a, b, c} 初始化
unordered_set(InputIt first, InputIt last)范围构造:用迭代器范围 [first, last) 初始化
unordered_set(const unordered_set& other)拷贝构造

示例

#include <iostream>
#include <unordered_set>
#include <vector>

int main() {
    // 1. 默认构造
    unordered_set<int> us1;

    // 2. 初始化列表构造
    unordered_set<int> us2 = {1, 2, 3, 4};

    // 3. 范围构造(从vector初始化)
    vector<int> vec = {5, 6, 7};
    unordered_set<int> us3(vec.begin(), vec.end());

    // 4. 拷贝构造
    unordered_set<int> us4(us2);

    return 0;
}

2. 迭代器与遍历

std::unordered_set 提供迭代器用于遍历元素,由于无序性,遍历顺序与插入顺序无关。

方法说明
begin() / cbegin()返回指向首元素的迭代器(cbegin() 为 const 版本)
end() / cend()返回指向尾后位置的迭代器

示例

unordered_set<int> us = {3, 1, 4, 1, 5}; // 重复的1会被自动去重
// 遍历元素(顺序不确定)
for (auto it = us.begin(); it != us.end(); ++it) {
    cout << *it << " "; // 可能输出:3 1 4 5 
}
cout << endl;

// C++11 范围for循环(更简洁)
for (int val : us) {
    cout << val << " "; // 输出顺序与上相同(同一次运行中)
}

3. 容量相关

用于判断容器状态或获取元素数量:

方法说明
empty()判断容器是否为空(空返回 true)
size()返回当前元素个数
max_size()返回容器理论上可存储的最大元素个数(受系统限制)

示例

unordered_set<string> us = {"apple", "banana"};
cout << "是否为空:" << (us.empty() ? "是" : "否") << endl; // 输出:否
cout << "元素个数:" << us.size() << endl; // 输出:2
cout << "最大容量:" << us.max_size() << endl; // 输出:约1e18(取决于系统)

4. 元素修改(插入、删除、清空)

这是 std::unordered_set 最核心的操作,用于维护容器中的元素。

方法说明
insert(val)插入元素 val,若已存在则忽略;返回 pair<iterator, bool>(迭代器指向元素,bool 表示是否插入成功)
insert(first, last)插入迭代器范围 [first, last) 中的元素
erase(val)删除值为 val 的元素,返回删除的个数(0 或 1)
erase(it)删除迭代器 it 指向的元素,返回下一个元素的迭代器
clear()清空所有元素
swap(other)交换当前容器与 other 的内容

示例

unordered_set<int> us;

// 插入元素
auto res1 = us.insert(10); 
cout << "插入10:" << (res1.second ? "成功" : "失败") << endl; // 成功

auto res2 = us.insert(10); // 插入重复值
cout << "再次插入10:" << (res2.second ? "成功" : "失败") << endl; // 失败

// 插入多个元素
us.insert({20, 30, 40});

// 删除元素(按值)
int del_count = us.erase(20);
cout << "删除20的个数:" << del_count << endl; // 1

// 删除元素(按迭代器)
auto it = us.find(30); // 先查找元素
if (it != us.end()) {
    us.erase(it); // 删除30
}

// 清空容器
us.clear();
cout << "清空后大小:" << us.size() << endl; // 0

5. 元素查找

用于判断元素是否存在或获取元素位置:

方法说明
find(val)查找值为 val 的元素,返回指向该元素的迭代器;若不存在,返回 end()
count(val)返回值为 val 的元素个数(0 或 1,因元素唯一)
contains(val)C++20 新增,判断元素 val 是否存在(返回 bool),比 count() 更直观

示例

unordered_set<string> fruits = {"apple", "banana", "cherry"};

// 查找元素
auto it = fruits.find("banana");
if (it != fruits.end()) {
    cout << "找到:" << *it << endl; // 找到:banana
} else {
    cout << "未找到" << endl;
}

// 计数(判断存在性)
if (fruits.count("orange") == 1) {
    cout << "存在orange" << endl;
} else {
    cout << "不存在orange" << endl; // 输出此句
}

// C++20 contains
if (fruits.contains("apple")) {
    cout << "存在apple" << endl; // 输出此句
}

6. 哈希策略相关

std::unordered_set 底层依赖哈希表,以下方法用于控制哈希表的性能:

方法说明
load_factor()返回当前负载因子(元素数 / 桶数),反映哈希表的拥挤程度
max_load_factor()返回或设置最大负载因子(默认值通常为 1.0)。当实际负载因子超过此值时,哈希表会自动扩容(重哈希)
rehash(n)强制将桶数设置为至少 n,可能触发重哈希
reserve(n)预分配空间,确保容器可容纳 n 个元素而无需重哈希(比 rehash() 更常用)

示例

unordered_set<int> us;

// 预分配空间(避免频繁重哈希)
us.reserve(1000); // 确保可容纳1000个元素

// 插入元素
for (int i = 0; i < 500; ++i) {
    us.insert(i);
}

cout << "当前负载因子:" << us.load_factor() << endl; // ~0.5(500/1000)
cout << "最大负载因子:" << us.max_load_factor() << endl; // 1.0

// 修改最大负载因子
us.max_load_factor(0.8);
cout << "修改后最大负载因子:" << us.max_load_factor() << endl; // 0.8

四、自定义类型的使用

std::unordered_set 存储自定义类型(如结构体)时,需满足两个条件:

  1. 提供哈希函数:告诉容器如何计算元素的哈希值;
  2. 提供相等比较函数:用于解决哈希碰撞(不同元素可能有相同哈希值)。

示例:存储自定义 Person 结构体

#include <string>

struct Person {
    string name;
    int age;

    // 定义相等比较(用于解决哈希碰撞)
    bool operator==(const Person& other) const {
        return name == other.name && age == other.age;
    }
};

// 特化 std::hash 用于 Person(提供哈希函数)
namespace std {
    template<> struct hash<Person> {
        size_t operator()(const Person& p) const {
            // 组合 name 和 age 的哈希值(简单实现)
            size_t h1 = hash<string>()(p.name);
            size_t h2 = hash<int>()(p.age);
            return h1 ^ (h2 << 1); // 哈希组合
        }
    };
}

int main() {
    unordered_set<Person> people;
    people.insert({"Alice", 25});
    people.insert({"Bob", 30});

    // 查找
    Person target = {"Alice", 25};
    if (people.contains(target)) {
        cout << "找到 Alice" << endl;
    }
    return 0;
}

五、与 std::set 的对比

特性std::unordered_setstd::set
底层实现哈希表红黑树(平衡二叉树)
元素顺序无序有序(默认升序)
插入/删除/查找复杂度平均 O(1),最坏 O(n)O(log n)
内存占用较高(哈希表需额外空间)较低
适用场景频繁查找、不关心顺序需要有序遍历、范围查询(如 lower_bound)

六、注意事项

  1. 哈希函数质量:差的哈希函数会导致大量碰撞,使性能退化到 O(n),需确保哈希值分布均匀;
  2. 元素不可修改std::unordered_set 的元素是 const 类型(修改会破坏哈希表结构),若需修改,需先删除再插入;
  3. 重哈希开销:当负载因子超过阈值时,容器会自动重哈希(重建哈希表),可能导致性能波动,可通过 reserve() 提前分配空间避免;
  4. 自定义类型要求:必须提供哈希函数和相等比较函数,否则编译报错。

到此这篇关于C++中unordered_set哈希集合的实现的文章就介绍到这了,更多相关C++ unordered_set哈希集合内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文