当前位置: 首页 > article >正文

unordered_map和 unordered_set

unordered系列关联式容器

在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2N log2N,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同。

关联式容器和序列式容器

在c++ 中关联式容器是一类标准模板库(stl)提供的容器类型,与序列容器不同,它主要用于存储元素,并且通过元素的键值(key) 来快速访问和操作这些元素。关联式容器的元素通常是基于键值排序的,以提供对特定元素的快速查找。

主要关联式容器

C++ 标准模板库提供了以下几种关联式容器:

  1. set
    • 定义set 是一个排序的容器,存储唯一元素。
    • 特点
      • 元素唯一,不存储重复值。
      • 元素按照升序或降序(默认升序)排列。
      • 提供对数级别的插入、删除和查找操作时间复杂度。
    • 使用场景:适用于需要存储唯一元素,并且需要按顺序访问或快速查找的场景。
  2. multiset
    • 定义:与set类似,但允许存储重复的元素。
    • 特点
      • 元素可以重复,允许同一值出现多次。
      • 元素按有序排列,相同的元素相邻。
      • set相同的时间复杂度。
    • 使用场景:适用于需要存储可重复元素,并且需要按顺序访问或快速查找的场景。
  3. map
    • 定义map 是一个键值对(Key-Value)的有序容器,每个键值对中的键是唯一的。
    • 特点
      • 键值对中的键(Key)唯一,值(Value)可以重复。
      • 根据键的升序或降序排列。
      • 提供通过键快速查找值的功能。
    • 使用场景:适用于需要通过键值快速查找对应值,并且键值对按顺序存储的场景。
  4. multimap
    • 定义:与map类似,但允许存储多个相同的键。
    • 特点
      • 键可以重复,允许同一键对应多个值。
      • 元素按有序排列,相同的键对应的元素相邻。
    • 使用场景:适用于需要存储可重复键,并且需要按顺序访问或快速查找的场景。

关联式容器与序列容器的区别

与序列容器(如vectorlist等)不同,关联式容器在存储和管理元素的方式上侧重于快速查找和有序存储,而序列容器更关注元素的线性排列和顺序访问。
关联式容器通常用于需要快速查找和有序存储的场景,例如:

  • 管理一个电话簿(使用map,键为姓名,值为电话号码)。
  • 统计学生的考试成绩(使用multiset,存储多个学生成绩,按顺序排列)。
  • 维护一个单词词典(使用set,存储唯一的单词)。

unordered_map

unordered_map 在线文档

我们之间也学过一个map 那这个unordered_map 和我们之前学的 map 有什么区别吗?

我们之前学的那个map 底层是红黑树,而这个unordered_map 底层是哈希,所以这样会更好理解一点:之前学的 map 我们可以称之为tree_map 。现在这个unordered_map 我们可以称之为hash_map ,之所以要叫unordered 这个名字,是因为这个unordered的单词意思是:无序。由于unorderde_map 的底层是哈希表所以它的元素是无序的,但是map的底层是红黑树,它的元素是有序的

unordered_map 是 C++ 标准模板库(STL)中的一个关联式容器,它基于哈希表(hash table)实现,存储键值对(key-value pairs)。unordered_map 的设计目标是在平均情况下提供较快速的插入、删除和查找操作。以下是对 unordered_map 的详细介绍:

1. 基本概念

  • 键值对存储unordered_map 中的每个元素都是一个键值对,键(key)是唯一的,值(value)可以重复。
  • 无序性:元素的存储顺序是无序的,这与 map(基于红黑树实现)的有序性不同。

2. 底层实现

  • 基于哈希表(hash table)实现。哈希表通过哈希函数将键映射到存储位置(桶),从而实现快速访问。
  • 如果不同的键被哈希到相同的存储位置(冲突),通常使用链地址法(拉链法)或开放地址法来解决冲突。

3. 主要特点

  • 高效查找、插入和删除:在平均情况下,unordered_map 的查找、插入和删除操作的时间复杂度为 O(1)。但在最坏情况下(哈希冲突频繁),时间复杂度可能为 O(N)。
  • 不保证元素顺序:元素的存储顺序是无序的,无法按特定顺序遍历元素。
  • 键的唯一性:每个键在 unordered_map 中只能出现一次。如果需要存储多个相同的键,可以使用 unordered_multimap

4. 常用操作

  • 插入元素:使用 insert()operator[] 插入键值对。
  • 查找元素:通过 operator[]at()find() 查找键对应的值。
  • 删除元素:使用 erase() 删除指定键的元素。
  • 遍历容器:通过迭代器遍历所有键值对。

5. 示例代码

#include <iostream>
#include <unordered_map>
using namespace std;

int main() {
    unordered_map<int, string> umap;

    // 插入元素
    umap[1] = "apple";
    umap[2] = "banana";
    umap[3] = "cherry";

    // 查找元素
    cout << "Key 2: " << umap[2] << endl;

    // 插入新元素
    umap.insert(pair<int, string>(4, "date"));

    // 遍历容器
    cout << "All elements:" << endl;
    for (auto& pair : umap) {
        cout << pair.first << ": " << pair.second << endl;
    }

    // 删除元素
    umap.erase(3);

    // 处理不存在的键
    if (umap.find(5) != umap.end()) {
        cout << "Key 5 found" << endl;
    } else {
        cout << "Key 5 not found" << endl;
    }

    return 0;
}

6. 适用场景

  • 快速查找和插入:适用于需要快速查找和插入键值对的场景,例如模拟数据库索引、字典等。
  • 大容量数据处理:由于高效的操作时间复杂度,适用于处理大量数据的场景。

unordered_map 是 C++ 中非常强大且灵活的容器之一,特别适用于需要快速查找和插入操作的场景。通过合理使用哈希函数,可以充分发挥其性能优势。

unordered_map是存储<key, value>键值对的关联式容器,其允许通过keys快速的索引到与其对应的value。
在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同。
在内部,unordered_map没有对<kye, value>按照任何特定的顺序排序, 为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。
unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。
unordered_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。
它的迭代器至少是前向迭代器。

unordered_map 接口说明

unordered_map 的构造

unordered_map 提供了多种构造方式:

1. 默认构造
unordered_map<int, std::string> myMap;

创建一个空的 unordered_map,键的类型为 int,值的类型为 std::string

2. 使用初始化列表构造
unordered_map<int, std::string> myMap = {
    {1, "Alice"},
    {2, "Bob"},
    {3, "Charlie"}
};

通过初始化列表直接填充 unordered_map

3. 通过范围构造
// 已经有一个范围,可以是数组、另一个容器等
std::vector<std::pair<int, std::string>> vec = {
    {1, "Apple"}, {2, "Banana"}, {3, "Cherry"}
};
unordered_map<int, std::string> myMap(vec.begin(), vec.end());

unordered_map 的容量

unordered_map 提供了以下函数来查询其容量:

1. empty()
if (myMap.empty()) {
    std::cout << "The map is empty." << std::endl;
}

检查 unordered_map 是否为空。

2. size()
std::cout << "The size is: " << myMap.size() << std::endl;

返回 unordered_map 中键值对的数量。

unordered_map 的迭代器

unordered_map 的迭代器支持以下操作:

1. begin()end()
for (auto it = myMap.begin(); it != myMap.end(); ++it) {
    std::cout << it->first << " : " << it->second << std::endl;
}

begin() 返回指向第一个元素的迭代器,end() 返回指向最后一个元素之后位置的迭代器。

2. cbegin()cend()
for (auto it = myMap.cbegin(); it != myMap.cend(); ++it) {
    std::cout << it->first << " : " << it->second << std::endl;
}

返回常量迭代器,用于只读访问。

unordered_map 的元素访问

unordered_map 提供了以下几种访问元素的方式:

1. operator[]
myMap[4] = "Date";
std::cout << myMap[4] << std::endl; // 输出 "Date"

如果键不存在,operator[] 会插入一个默认构造的值。

2. at()
try {
    std::cout << myMap.at(5) << std::endl;
} catch (const std::out_of_range& e) {
    std::cout << "Key not found." << std::endl;
}

at() 会检查键是否存在,如果不存在,会抛出 std::out_of_range 异常。

unordered_map 的查询

unordered_map 提供了以下查询函数:

1. find()
auto it = myMap.find(2);
if (it != myMap.end()) {
    std::cout << "Found: " << it->second << std::endl;
}

find() 返回一个迭代器,指向键对应的元素,如果找不到则返回 end()

2. count()
if (myMap.count(3) > 0) {
    std::cout << "Key 3 exists." << std::endl;
}

count() 返回键对应的元素数目,对于 unordered_map 来说,通常是 0 或 1。

unordered_map 的修改操作

unordered_map 支持以下修改操作:

1. insert()
myMap.insert({4, "Elderberry"}); // 插入一个键值对
2. erase()
myMap.erase(1); // 删除键为 1 的元素
3. clear()
myMap.clear(); // 清空所有元素

unordered_map 的桶操作

unordered_map 内部使用桶(bucket)来组织数据。以下是一些桶操作:

1. bucket_count()
std::cout << "Number of buckets: " << myMap.bucket_count() << std::endl;

bucket_count:返回哈希表中桶的数量。

2. bucket_size()
std::cout << "Bucket 0 size: " << myMap.bucket_size(0) << std::endl;

bucket_size:返回第 n 个桶中的元素数目。

3. bucket()
std::cout << "Key 2 is in bucket: " << myMap.bucket(2) << std::endl;

bucket:返回键对应桶的索引。

unordered_set 的介绍

unordered_set 是 C++ 标准库中的一个容器,它存储唯一的元素,不保存任何顺序。与 set 不同,unordered_set 内部使用哈希表结构,因此在查询、插入和删除操作时具有更快的平均时间复杂度,通常为 O(1)。

1.1 unordered_set 的用途

当你需要存储一组不重复的元素,并且希望快速判断某个元素是否存在时unordered_set 是一个理想的选择。例如,在处理大量数据时快速过滤重复元素。

1.2 unordered_set 的构造

unordered_set 提供了多种构造方法:

1. 默认构造

unordered_set<int> mySet;

这会创建一个空的 unordered_set,键的类型为 int

2. 使用初始化列表构造

unordered_set<int> mySet = {1, 2, 3, 4, 5};

通过初始化列表直接填充 unordered_set

3. 通过范围构造

std::vector<int> vec = {10, 20, 30, 40, 50};
unordered_set<int> mySet(vec.begin(), vec.end());

1.3 unordered_set 的容量

unordered_set 提供了以下函数来查询其容量:

1. empty()

if (mySet.empty()) {
    std::cout << "The set is empty." << std::endl;
}

检查 unordered_set 是否为空。

2. size()

std::cout << "The size is: " << mySet.size() << std::endl;

返回 unordered_set 中元素的数量。

1.4 unordered_set 的迭代器

unordered_set 的迭代器支持以下操作:

1. begin()end()

for (auto it = mySet.begin(); it != mySet.end(); ++it) {
    std::cout << *it << " ";
}

begin() 返回指向第一个元素的迭代器,end() 返回指向最后一个元素之后位置的迭代器。

2. cbegin()cend()

for (auto it = mySet.cbegin(); it != mySet.cend(); ++it) {
    std::cout << *it << " ";
}

返回常量迭代器,用于只读访问。

1.5 unordered_set 的元素访问

unordered_set 提供了以下几种查询元素的方式:

1. find()

auto it = mySet.find(3);
if (it != mySet.end()) {
    std::cout << "Found: " << *it << std::endl;
}

find() 返回一个迭代器,指向键对应的元素,如果找不到则返回 end()

2. count()

if (mySet.count(5) > 0) {
    std::cout << "Key 5 exists." << std::endl;
}

count() 返回键对应的元素数目,对于 unordered_set 来说,通常是 0 或 1。

1.6 unordered_set 的修改操作

unordered_set 支持以下修改操作:

1. insert()

mySet.insert(6); // 插入单个元素
mySet.insert({7, 8, 9}); // 插入多个元素

2. erase()

mySet.erase(2); // 删除单个元素

3. clear()

mySet.clear(); // 清空所有元素

1.7 unordered_set 的桶操作

unordered_set 内部使用桶(bucket)来组织数据。以下是一些桶操作:

1. bucket_count()

std::cout << "Number of buckets: " << mySet.bucket_count() << std::endl;

2. bucket_size()

std::cout << "Bucket 0 size: " << mySet.bucket_size(0) << std::endl;

3. bucket()

std::cout << "Key 2 is in bucket: " << mySet.bucket(2) << std::endl;

http://www.kler.cn/a/557714.html

相关文章:

  • 20250221 NLP
  • 基于C++ Qt的图形绘制与XML序列化系统
  • HW面试经验分享 | 北京蓝中研判岗
  • 【Java】File 类
  • 水果生鲜农产品推荐系统 协同过滤余弦函数推荐水果生鲜农产品 Springboot Vue Element-UI前后端分离 代码+开发文档+视频教程
  • WPF实现打印机控制及打印
  • ACWing蓝桥杯集训·每日一题2025-6122. 农夫约翰的奶酪块-Java
  • malloc如何分配内存
  • 区块链相关方法-SWOT分析
  • DeepSeek底层揭秘——微调
  • Linux基本指令(三)+ 权限
  • w223信息技术知识赛系统设计与实现
  • 【Python爬虫(47)】探秘分布式爬虫性能:从测试到优化之路
  • 清华大学第五弹:《DeepSeek与AI幻觉》
  • Python strip() 方法详解:用途、应用场景及示例解析(中英双语)
  • 【多模态处理篇三】【DeepSeek语音合成:TTS音色克隆技术揭秘】
  • [VSCode]彻底卸载和重装,并搭建Java开发环境
  • 内容中台重构企业内容管理的价值维度与实施路径
  • Power Query M函数
  • rtcwake - Linux下定时唤醒计算机