C++ unordered系列
本文围绕C++中unordered系列容器展开,先介绍序列式与关联式容器的区别,前者按插入顺序存储,后者者按键存储。还讲解了pair类型的概念、实现、创建初始化及访问方式。重点阐述哈希表,包括其定义、负载因子、哈希函数、冲突解决方法及代码实现。此外,详细说明了unordered_set和unordered_map的原型、成员函数(构造函数、赋值重载等),以及它们与对应的multiset、multi
C++unordered系列
1. 序列式容器和关联式容器
1.1 序列式容器
序列式容器按照线性顺序存储元素,元素的位置取决于插入的时间和位置,与元素的值无关。
主要特点:
-
元素按插入顺序存储
-
可以通过位置(索引)直接访问元素
-
不自动排序
-
允许重复元素
常见的序列式容器:
-
array(C++11)
-
固定大小的数组
-
内存连续分配
-
大小在编译时确定
-
快速随机访问
-
-
vector
-
动态数组
-
内存连续分配
-
可动态扩展
-
在尾部插入/删除高效
-
支持快速随机访问
-
-
deque(双端队列)
-
双端可扩展
-
内存分段连续
-
在头尾插入/删除高效
-
支持快速随机访问(比vector稍慢)
-
-
list
-
双向链表
-
内存非连续分配
-
在任何位置插入/删除高效
-
不支持随机访问
-
-
forward_list(C++11)
-
单向链表
-
内存非连续分配
-
更节省空间
-
只支持单向遍历
-
1.2 关联式容器
关联式容器按照特定顺序存储元素,元素的顺序取决于元素的键(key),而不是插入的顺序。
主要特点:
-
元素按特定顺序(平衡二叉搜索树或哈希)存储
-
通过键(key)快速查找元素
-
通常实现为平衡二叉搜索树或哈希表
-
有些版本不允许重复元素
常见的关联式容器:
-
有序关联容器(基于红黑树实现)
-
set:唯一键的集合,按键排序
-
map:键值对集合,按键排序,键唯一
-
multiset:键可重复的set
-
multimap:键可重复的map
-
-
无序关联容器(C++11引入,基于哈希表实现)
-
unordered_set:唯一键的集合,基于哈希
-
unordered_map:键值对集合,基于哈希,键唯一
-
unordered_multiset:键可重复的unordered_set
-
unordered_multimap:键可重复的unordered_map
-
2. 认识pair类型
2.1 概念
pair是C++标准模板库(STL)中的一个实用模板类,用于将两个值组合成一个单一对象,可以存储两个不同类型的元素,称为first和second。这两个值可以是相同类型,也可以是不同类型。它定义在<utility>头文件中,是许多STL容器(如map、unordered_map)的基础构建块。
2.2 pair实现
template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
first_type first;
second_type second;
pair(): first(T1()), second(T2()) {} // 默认构造
pair(const T1& a, const T2& b): first(a), second(b) {}
template<class U, class V>
pair (const pair<U,V>& pr): first(pr.first), second(pr.second) {} // 拷贝构造
};
为什么拷贝构造需要使用类中内嵌模板?
template <typename U1, typename U2> pair(const pair<U1, U2>& p); 这个构造函数的存在是为了支持跨类型的拷贝构造,而不仅仅是同类型的拷贝构造。这是 C++ 模板类设计中的一个重要特性,称为转换构造函数。
-
类型转换支持:
-
允许从
pair<U1, U2>构造pair<T1, T2> -
只要
U1可以转换为T1,U2可以转换为T2
-
-
场景:
std::pair<int, double> p1(42, 3.14); std::pair<long, float> p2(p1); // 需要这个模板构造函数 -
与普通拷贝构造的区别:
-
普通拷贝构造:
pair(const pair<T1, T2>& p) -
模板拷贝构造:
template <typename U1, typename U2> pair(const pair<U1, U2>& p)
-
-
如果没有这个模板拷贝构造函数会怎么样?
std::pair<int, std::string> p1(1, "hello"); std::pair<double, const char*> p2(p1); // 编译错误 // 因为没有从 pair<int,string> 到 pair<double,const char*> 的转换路径
2.3 创建和初始化pair
2.3.1 构造函数
std::pair<int, std::string> p1(1, "apple");
2.3.2 使用make_pair函数(自动推导类型)
make_pair函数模板原型:
template <class T1,class T2>
inline pair<T1,T2> make_pair (T1 x, T2 y)
{
return ( pair<T1,T2>(x,y) );
}
auto p2 = std::make_pair(2, "banana");
2.3.3 C++11-initializer_list初始化
std::pair<int, std::string> p3 = {3, "cherry"};
2.4 访问pair成员
通过 first 和 second 访问成员。
2.4.1 普通访问
std::pair<int, std::string> p(1, "apple");
std::cout << "First: " << p.first << std::endl; // 输出: First: 1
std::cout << "Second: " << p.second << std::endl; // 输出: Second: apple
2.4.2 结构化绑定(C++17)
auto p = std::make_pair(3.14, "pi");
auto [value, name] = p; // value=3.14, name="pi"
3. 哈希表
3.1 什么是哈希表?
哈希表又称散列,是一种能够提供平均情况下近乎常数时间复杂度 O(1) 进行插入、删除和查找操作的数据结构。
它的核心思想是:通过一个函数(哈希函数)将数据(键,Key)映射到一个固定大小的数组的某个索引位置。通常的实现方式有闭散列和开散列。
-
哈希表中的key需要能转换成为一个整数
-
并且哈希表中的key需要支持 == 的比较
库中提供了对应的仿函数来实现。
3.2 负载因子
在哈希表(Hash Table)的设计与优化中,负载因子(Load Factor) 是衡量哈希表 拥挤程度 的核心指标,直接影响哈希冲突的概率和哈希表的性能。
负载因子=N/M负载因子 = N / M负载因子=N/M
- 已存储键值对数量(N):当前哈希表中实际存放的有效数据个数。
- 哈希表总容量(M):哈希表预设的最大存储位置数(例如数组长度)。
3.3 哈希函数
哈希函数(Hash Function)是一种将任意大小、任意类型的数据(key)映射到固定大小位置 的函数。
3.3.1 除留余数法
取关键字(Key)除以某个数 m 的余数,作为其哈希值(即哈希表的索引)。
公式:hash(key)=keymod mhash(key)=key\mod\ mhash(key)=keymod m
-
key 是输入的关键字(通常需要先转换为一个整数)。
-
m 是数组的大小。
**黄金法则:模数 m 应该是一个质数(Prime Number),并且不能太接近 2 的幂次方。
3.4 哈希冲突
哈希冲突(Hash Collision) 是哈希表(Hash Table)等哈希技术中不可避免的现象,指的是不同的输入键(Key)经过哈希函数(Hash Function)计算后,得到了相同的哈希值(Hash Value)。
针对哈希冲突,常见的解决方法可分为两大类:开放定址法和链地址法
3.4.1 开放定址法(Open Addressing)
当发生哈希冲突时,通过某种探测规则在哈希表中寻找下一个空闲位置存储数据,而不是直接存在哈希值对应的位置。核心思想是 冲突后继续寻找空位。
常见的探测方式包括:
- 线性探测(Linear Probing):若哈希值为
h的位置已被占用,则依次检查h+1、h+2…… 直到找到空闲位置。- 优点:实现简单,缓存利用率高;
- 缺点:容易产生 聚集现象(多个冲突键集中在某一区域,导致后续探测效率下降)。
- 二次探测(Quadratic Probing):冲突时,探测位置为
h+i²或h-i²(i为探测次数),避免线性探测的聚集问题。- 优点:分散冲突位置,减少聚集;
- 缺点:可能无法探测到所有空闲位置(取决于哈希表大小)。
- 双重哈希(Double Hashing):使用第二个哈希函数计算探测步长,步长随键变化(例如
step = hash2(key)),进一步降低聚集风险。- 优点:冲突分布更均匀,适合大规模数据;
- 缺点:实现复杂,需设计两个哈希函数。
3.4.2 链地址法(Chaining,又称拉链法)
将哈希值相同的键值对存储在同一个链表中,哈希表的每个位置指向一个链表的头节点。核心思想是 冲突键集中存储。
- 工作流程:
- 键通过哈希函数得到哈希值
h,定位到哈希表的索引h; - 若索引
h处已有数据,则将新键值对插入该位置的链表尾部(或头部); - 查询时,先定位到索引
h,再遍历链表查找目标键。
- 键通过哈希函数得到哈希值
- 优点:
- 不会产生聚集现象,插入删除效率高(链表操作);
- 哈希表利用率高,无需预留大量空闲位置。
- 缺点:
- 链表过长时,查询效率会退化(从 O (1) 趋近于 O (n));
- 额外存储链表指针,内存开销略大。
实际应用:Java 的HashMap、Python 的字典(Dict)均采用链地址法,当链表长度超过阈值(默认 8)时,会将链表转为红黑树,进一步优化查询效率。
3.5 代码实现
#pragma once
#include <algorithm>
#include <iostream>
#include <vector>
#include <utility>
#include <string>
namespace hash_bucket {
inline unsigned long __stl_next_prime(unsigned long n) {
// Note: assumes long is at least 32 bits.
static const int __stl_num_primes = 28;
static const unsigned long __stl_prime_list[__stl_num_primes] = {
53, 97, 193, 389, 769,
1543, 3079, 6151, 12289, 24593,
49157, 98317, 196613, 393241, 786433,
1572869, 3145739, 6291469, 12582917, 25165843,
50331653, 100663319, 201326611, 402653189, 805306457,
1610612741, 3221225473, 4294967291
};
const unsigned long* first = __stl_prime_list;
const unsigned long* last = __stl_prime_list + __stl_num_primes;
const unsigned long* pos = std::lower_bound(first, last, n);
return pos == last ? *(last - 1) : *pos;
}
template<typename Key>
struct HashK {
size_t operator()(const Key& key) { return (size_t)key; }
};
template<>
struct HashK<std::string> {
size_t operator()(const std::string& key) {
size_t res = 0;
for (auto c : key) {
res += c * 131;
}
return res;
}
};
template<typename Key , typename Value>
struct HashTableNode {
std::pair<Key , Value> data;
HashTableNode<Key , Value>* next;
HashTableNode(const std::pair<Key , Value>& _data) :data(_data) , next(nullptr) {}
};
template<typename Key>
struct IsEqualKey {
bool operator()(const Key& k1 , const Key& k2) {
return k1 == k2;
}
};
// 前置声明
// 默认参数只能在声明时写,不能在定义时写
template<typename Key , typename Value , typename HashKey = HashK<Key> , typename EqualKey = IsEqualKey<Key>>
class HashTable;
template<typename Key , typename Value , typename Ref , typename Ptr , typename HashKey = HashK<Key> , typename EqualKey = IsEqualKey<Key>>
struct HashIterator {
using HashNode = HashTableNode<Key , Value>;
using Ht = HashTable<Key , Value , HashKey , EqualKey>;
using Self = HashIterator<Key , Value , Ref , Ptr , HashKey , EqualKey>;
HashNode* cur;
Ht* ht;
HashIterator(HashNode* node , Ht* _ht) :cur(node) , ht(_ht) {}
// 前置++
Self& operator++() {
if (cur->next) {
cur = cur->next;
} else {
size_t key = HashKey()(cur->data.first) % ht->table.size();
key++;
while (key < ht->table.size() && !ht->table[key]) {
key++;
}
if (key == ht->table.size()) {
cur = nullptr;
} else {
cur = ht->table[key];
}
}
return *this;
}
Ref operator* () {
return cur->data;
}
Ptr operator-> () {
return &(cur->data);
}
bool operator== (const Self& s) {
return cur == s.cur;
}
bool operator!= (const Self& s) {
return cur != s.cur;
}
};
// HashKey仿函数:将key转换为无符号整数
// EqualKey仿函数:key需要支持 == 运算符
template<typename Key , typename Value , typename HashKey , typename EqualKey>
class HashTable {
// 内层友元模板,不能和外层HashTable模板参数相同
template<typename K2 , typename V2 , typename Ref2 , typename Ptr2 , typename HK2 , typename EK2>
friend struct HashIterator;
using HashNode = HashTableNode<Key , Value>;
public:
typedef HashIterator<Key , Value , std::pair<Key , Value>& , std::pair<Key , Value>* , HashKey , EqualKey> iterator;
// using iterator = ;
using const_iterator = HashIterator<Key , Value , const std::pair<Key , Value>& , const std::pair<Key , Value>* , HashKey , EqualKey>;
iterator begin() {
if (n == 0) {
return end();
}
for (size_t i = 0; i < table.size(); i++) {
if (table[i]) {
return iterator(table[i], this);
}
}
return end();
}
iterator end() {
return iterator(nullptr , this);
}
HashTable()
:table(__stl_next_prime(0)) , n(0)
{}
~HashTable() {
for (size_t i = 0; i < table.size(); i++) {
HashNode* cur = table[i];
while (cur) {
HashNode* next = cur->next;
delete cur;
cur = next;
}
table[i] = nullptr;
}
}
HashTable(const HashTable& ht) {
table.resize(ht.table.size());
n = ht.n;
for (size_t i = 0; i < ht.table.size(); i++) {
HashNode* cur = ht.table[i];
if (!cur) {
table[i] = nullptr;
continue;
}
while (cur) {
HashNode* newnode = new HashNode(cur->data);
newnode->next = table[i];
table[i] = newnode;
cur = cur->next;
}
}
}
HashTable& operator=(HashTable ht) {
table.swap(ht.table);
std::swap(n , ht.n);
return *this;
}
bool insert (const std::pair<Key , Value>& data) {
if (find(HashKey()(data.first))) return false; // 存在相同元素,不插入
// 负载因子为1时,hash需要扩容
if (n == table.size()) {
std::vector<HashNode*> newTable(__stl_next_prime(table.size() + 1));
// 将旧表中的节点依次转移到新表
for(auto head : table) {
HashNode* cur = head;
while (cur) {
HashNode* next = cur->next;
size_t key = HashKey()(cur->data.first) % newTable.size();
cur->next = newTable[key];
newTable[key] = cur;
cur = next;
}
head = nullptr;
}
// 交换旧表和新表
table.swap(newTable);
}
// 添加新节点
HashNode* newnode = new HashNode(data);
size_t key = HashKey()(data.first) % table.size();
newnode->next = table[key];
table[key] = newnode;
n++;
return true;
}
bool erase(const Key& key) {
size_t hashIndex = HashKey()(key) % table.size();
HashNode* prev = nullptr;
HashNode* cur = table[hashIndex];
while (cur) {
// 删除需要区分头删还是中间节点删除
if (EqualKey()(HashKey()(cur->data.first) , HashKey()(key))) {
if (!prev) {
// 头删
table[hashIndex] = cur->next;
} else {
// 中间节点删除
prev->next = cur->next;
}
delete cur;
return true;
} else {
// 迭代继续寻找
prev = cur;
cur = cur->next;
}
}
return false;
}
bool find (const Key& key) {
size_t hashIndex = HashKey()(key) % table.size();
HashNode* cur = table[hashIndex];
while (cur) {
if (EqualKey()(HashKey()(cur->data.first) , HashKey()(key))) return true;
cur = cur->next;
}
return false;
}
private:
std::vector<HashNode*> table;
size_t n;
};
} // end namespace hash_bucket
4. unordered_set
unordered_set是C++ STL中的关联式容器,它存储唯一元素(key)并自动去重。
unordered_set原型
template <
class Key,
class Hash = hash<Key>, // unordered_set::hasher
class Pred = equal_to<Key>, // unordered_set::key_equal
class Alloc = allocator<Key> // unordered_set::allocator_type
> class unordered_set;
-
Key就是unordered_set底层关键字的类型
-
unordered_set默认要求Key⽀持转换为整形,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现⽀持将Key转成整形的仿函数传给第⼆个模板参数
-
unordered_set默认要求Key⽀持⽐较相等,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现⽀持将Key⽐较相等的仿函数传给第三个模板参数
4.1 成员函数
4.1.1 成员类型
| 成员类型 | 解释 |
|---|---|
| key_type | 第一个模板参数Key |
| value_type | 第一个模板参数Key |
4.1.2 构造函数
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | explicit unordered_set ( size_type n = / see below /, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& alloc = allocator_type() ) | 默认构造 |
| 2️⃣ | unordered_set ( const unordered_set& ust ) | 拷贝构造 |
| 3️⃣ | unordered_set ( initializer_list<value_type> il, size_type n = / see below /, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& alloc = allocator_type() ) | 使用 initializer_list 初始化 |
| 4️⃣ | template <class InputIterator> unordered_set ( InputIterator first, InputIterator last, size_type n = /* see below */, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& alloc = allocator_type() ) | 使用一段迭代器区间初始化 |
n = /* see below */:第一个参数有默认值(具体值由实现定义,通常是某个初始桶数)。
4.1.3 赋值重载
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | unordered_set& operator= ( const unordered_set& ust ) | 两个已存在的 unordered_set 对象的赋值 |
| 2️⃣ | unordered_set& operator= ( intitializer_list<value_type> il ) | 使用 initializer_list 赋值 |
4.1.4 迭代器
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | iterator begin() | 返回指向 unordered_set 对象中第一个元素的迭代器 |
| 2️⃣ | const_iterator begin() const | 返回指向 unordered_set 对象中第一个元素的 const 迭代器 |
| 3️⃣ | iterator end() | 返回指向 unordered_set 对象末尾元素之后位置的迭代器 |
| 4️⃣ | const_iterator end() const | 返回指向 unordered_set 对象末尾元素之后位置的 const 迭代器 |
unordered_系列是单向迭代器。
4.1.5 容量相关的接口
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | bool empty() const | 判断 unordered_set 对象是否为空 |
| 2️⃣ | size_type size() const | 返回 unordered_set 对象中元素的数量 |
4.1.6 修改相关的接口
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | pair<iterator,bool> insert (const value_type& val) | 向 unordered_set 对象中插入 val 元素 |
| 2️⃣ | iterator erase (const_iterator position) | 删除 unordered_set 对象中 position 迭代器位置元素,返回删除元素的下一个有效迭代器 |
| 3️⃣ | size_type erase (const key_type& val) | 删除 unordered_set 对象中 val 元素,返回值返回为删除的 val 元素(0或1) |
| 4️⃣ | void clear() | 清空 unordered_set 对象 |
pair<iterator,bool> insert (const value_type& val)返回值解析返回值是一个
std::pair,包含两个部分:
iterator:指向插入元素的迭代器
如果插入成功:指向新插入的元素
如果插入失败(元素已存在):指向已存在的元素
bool:表示插入是否成功
true:元素被成功插入
false:元素已存在,未插入新元素
4.1.7 其他
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | iterator find (const value_type& val) | 在 unordered_set 对象中查找 val 元素,成功返回该位置迭代器,失败返回迭代器end() |
| 2️⃣ | size_type count (const value_type& val) const | 返回 unordered_set 对象中 val 元素的数量(0或1) |
4.2 unordered_set与unordered_multiset的区别
unordered_set和unordered_multiset都是C++ STL中的关联容器,它们的主要区别在于元素的唯一性。
主要区别
-
元素唯一性
-
unordered_set:存储唯一元素,不允许重复 -
unordered_multiset:允许存储重复元素
-
-
插入操作
-
向
unordered_set插入已存在元素时,插入操作会失败 -
向
unordered_multiset可以重复插入相同元素
-
-
count()返回值-
unordered_set:只能是 0 或 1 -
unordered_multiset:可以是 0, 1, 或任意正整数
-
-
erase() 返回值
-
unordered_set:删除的元素个数(0 或 1) -
unordered_multiset:删除的所有该元素的总个数
-
- unordered_set与unordered_multiset接口一致。
5. unordered_map
unordered_map 是C++标准模板库(STL)中的一个关联容器,它存储的元素是pair类型,并且根据键(key)自动去重。
unordered_map原型
template < class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>, class Alloc = allocator<pair<const Key,T>>> class unordered_map;
unordered_map中存储的pair类型
typedef pair<const Key, T> value_type;
-
Key就是map底层关键字的类型,T是map底层value的类型
-
unordered_map默认要求Key⽀持转换为整形,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现⽀持将Key转成整形的仿函数传给第三个模板参数
-
unordered_map默认要求Key⽀持⽐较相等,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现⽀持将Key⽐较相等的仿函数传给第四个模板参数
5.1 成员函数
5.1.1 成员类型
| 成员类型 | 解释 |
|---|---|
| key_type | 第一个模板参数Key |
| mapped_type | 第二个模板参数T |
5.1.2 构造函数
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | explicit unordered_map ( size_type n = / see below /, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& alloc = allocator_type() );explicit unordered_map ( const allocator_type& alloc ) | 默认构造 |
| 2️⃣ | unordered_map ( const unordered_map& ump ) | 拷贝构造 |
| 3️⃣ | unordered_map ( initializer_list<value_type> il, size_type n = / see below /, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& alloc = allocator_type() ) | 使用 initializer_list 初始化 |
| 4️⃣ | template <class InputIterator> unordered_map ( InputIterator first, InputIterator last, size_type n = /* see below */, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& alloc = allocator_type() ) | 使用一段迭代器区间初始化 |
n = /* see below */:第一个参数有默认值(具体值由实现定义,通常是某个初始桶数)。
5.1.3 赋值重载
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | unordered_map& operator= ( const unordered_map& ump ) | 两个已存在的 unordered_map 对象的赋值 |
| 2️⃣ | unordered_map& operator= ( intitializer_list<value_type> il ) | 使用 initializer_list 赋值 |
5.1.4 迭代器
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | iterator begin() | 返回指向 unordered_map 对象中第一个元素的迭代器 |
| 2️⃣ | const_iterator begin() const | 返回指向 unordered_map 对象中第一个元素的 const 迭代器 |
| 3️⃣ | iterator end() | 返回指向 unordered_map 对象末尾元素之后位置的迭代器 |
| 4️⃣ | const_iterator end() const | 返回指向 unordered_map 对象末尾元素之后位置的 const 迭代器 |
unordered_系列是单向迭代器。
5.1.5 容量相关的接口
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | bool empty() const | 判断 unordered_map 对象是否为空 |
| 2️⃣ | size_type size() const | 返回 unordered_map 对象中元素的数量 |
5.1.6 元素的访问
| 序号 | 函数原型 |
|---|---|
| 1️⃣ | mapped_type& operator[] (const key_type& k) |
unordered_map 的 operator[] 是一个非常有用的成员函数,它提供了对映射值的快速访问和修改能力。
功能说明
-
查找与修改:如果键
k存在于 map 中,返回对应的映射值(value)的引用 -
插入与修改:如果键
k不存在,会自动插入一个新的键值对,键为k,值为mapped_type的默认构造值,然后返回这个新值(value)的引用
operator[]实现
(*( (insert(make_pair(k,mapped_type()))).first).second)
解析
mapped_type& operator[] (const key_type& k) {
pair<iterator, bool> ret = insert({ k, mapped_type() });
iterator it = ret.first;
return it->second;
}
5.1.7 修改相关的接口
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | pair<iterator,bool> insert (const value_type& val) | 向 unordered_map 对象中插入 val 元素 |
| 2️⃣ | iterator erase (const_iterator position) | 删除 unordered_map 对象中 position 迭代器位置元素,返回删除元素的下一个有效迭代器 |
| 3️⃣ | size_type erase (const key_type& val) | 删除 unordered_map 对象中 val 元素,返回值返回为删除的 val 元素(0或1) |
| 4️⃣ | void clear() | 清空 unordered_map 对象 |
pair<iterator,bool> insert (const value_type& val)返回值解析返回值是一个
std::pair,包含两个部分:
iterator:指向插入元素的迭代器
如果插入成功:指向新插入的元 素
如果插入失败(元素已存在):指向已存在的元素
bool:表示插入是否成功
true:元素被成功插入
false:元素已存在,未插入新元素
5.1.8 其他
| 序号 | 函数原型 | 说明 |
|---|---|---|
| 1️⃣ | iterator find (const value_type& val) | 在 unordered_map 对象中查找 val 元素,成功返回该位置迭代器,失败返回迭代器end() |
| 2️⃣ | size_type count (const value_type& val) const | 返回 unordered_map 对象中 val 元素的数量(0或1) |
5.2 unordered_map与unordered_multimap的区别
unordered_map和unordered_multimap都是C++ STL中的关联容器,它们的主要区别在于元素的唯一性。
主要区别
-
元素唯一性
-
unordered_map:存储唯一元素,不允许重复 -
unordered_multimap:允许存储重复元素
-
-
插入操作
-
向
unordered_map插入已存在元素时,插入操作会失败 -
向
unordered_multimap可以重复插入相同元素
-
-
operator[]
-
unordered_map:支持operator[]访问 -
unordered_multimap:不支持operator[],因为键不唯一
-
- map与multimap接口一致。
更多推荐


所有评论(0)