C++ 标准模板库 STL 组件(Component)—— container(下)Unordered Container 无序容器

 介绍

概念上来说, unordered 容器以一种随意顺序包含你安插进去的所有元素,相比于 set/multiset 和 map/multimap 而言,不需要排序准则;相比于 sequence 容器,没有语义可以用来放置元素到指定位置

像 associate 容器一样,个别 class 会有不同:

  • Unordered set 和 multiset 存放的都是某特定类型的个别 value,而 Unordered map 和 multimap 存放的元素是 key/value 的 pair 类型,其中一般 key 为查找或存放依据
  • Unordered set 和 map 不允许存放相同数据,但 Unordered map 和 multimap 允许

头文件:

  • #include <unordered_set>
  • #include <unordered_map>

定义:

namespace std{
    template <typename T,
              typename Hash = hash<T>,
              typename EqPred = equal_to<T>,
              typename Allocator = allocator<T>>
            class unordered_set;

    template <typename T,
              typename Hash = hash<T>,
              typename EqPred = equal_to<T>,
              typename Allocator = allocator<T>>
            class unordered_multiset;

    template <typename Key, typename Value
              typename Hash = hash<T>,
              typename EqPred = equal_to<T>,
              typename Allocator = allocator<T>>
            class unordered_map;

    template <typename Key, typename Value
              typename Hash = hash<T>,
              typename EqPred = equal_to<T>,
              typename Allocator = allocator<T>>
            class unordered_multimap;
}

template Hash 类型是哈希函数,如果不自定义则会默认使用标准库的 hash

template Eqpred 是定义等价准则:这是一个判断式,用来查找元素来判断两个 value 是否相等,如果没有自定义则默认使用 equal_to<> ,它会以 operator == 比较两个元素

Unordered 容器能力

所有标准化 unordered container class 但是以 hash table 为基础,并基于以下假设:

  • hash table 采用 chaining(链表)做法,于是一个 hash code 将会被关联到一个 linked list
  • 该 linked list 的链类型取决于实现,C++ standard 仅仅保证它们的 iterator 至少是 forward iterator
  • 关于 rehashing,有不同的实现策略:(1)在单一的 insert 或 erase 动作出现时,有时会发生一次 rehash;(2)渐进地改变 hash table的大小

内部结构

 

这里展示了 Unordered 容器的典型内部结构,我们可以发现对于每个将被存放的元素,hash function 会把 key 映射至 hash table 内的某个 bucket 中,然后每个 bucket 都管理一个 单向的 linked list,内含经过 hash function 产生相同结果的元素

在不存在哈希冲突的情况下,可以以常数级别的时间复杂度进行删除、查询等操作

创造和控制 Unordered 容器

创造、复制和销毁

Unord c

Default 默认构造函数

Unord c(bnum)建立一个内部至少有 bnum 个 bucket 的容器
Unord c(bnum,hf)建立一个内部至少有 bnum 个 bucket 的容器,并且以 hf 为 hash function
Unord c(bnum, hf cmp)建立一个内部至少有 bnum 个 bucket 的容器,并且以 hf 为 hash function,并以 cmp 为等价准则
Unord c(c2)

Copy 构造函数

Unord c = (c2)Copy 构造函数
Unord c(rv)Move 构造函数
Unord c = rvMove 构造函数
Unord c(beg,end)以区间[beg,end)内的数值为初值构造
Unord c(beg,end,bnum)以区间[beg,end)内的数值为初值构造,并且内部至少有 bnum 个 bucket
Unord c(beg,end,bnum,hf)以区间[beg,end)内的数值为初值构造,并且内部至少有 bnum 个 bucket,并且以 hf 为 hash function
Unord c(beg,end,bnum,hf,cmp)以区间[beg,end)内的数值为初值构造,并且内部至少有 bnum 个 bucket,并且以 hf 为 hash function,并以 cmp 为等价准则
Unord c(initlist)以初值列 initlist 为初值构造
Unord c = initlist以初值列 initlist 为初值构造
c.~Unord()析构函数
c.max_load_factor(float)设置最大负荷系数

布局操作

c.hash_function()返回 hash() 函数
c.key_eq()返回 “相等性判断式”

c.bucket_count()

返回当前 bucket 数量
c.max_bucket_count()返回最大可能 bucket 数量
c.load_factor()返回当前负载系数
c.max_load_factor()返回当前最大负载系数
c.max_load_factor(val)设置最大负载系数
c.rehash(bnum)将容器 rehash ,使其 bucket 个数至少为 bnum
c.reserve(num)将容器 rehash,使其空间至少拥有 num 个元素

rehash 和 reserve的区别:

  • rehash 传入的 bnum值 是允许最大容量 除于最大负载系数的值
  • reserve 传入的 num值 可以直接为 最大容量(即rehash的界限)

 非更易型操作(Nonmodifying Operation)

c.empty()返回容器是否为空
c.size()返回目前元素个数
c,max_size()返回元素个数的最大可能
c1 == c2

判断 c1 是否等于 c2

c1 != c2判断 c1 是否不等于 c2

特殊的查找操作(Special Search Operator)

c.count(val)返回 元素值为 val 的元素个数
c.find(val)返回 元素值为 val 的第一个元素,找不到则返回 val
c.equal_range(val)返回 val 可被安插的第一个位置和最后一个位置,也就是 元素值 == val 的区间

Assignment

c = c2

将 c2 全部元素赋值给 c1

c = rvmove assignment
c = initlist将初值列 的所有元素赋值给 c
c1.swap(c2)置换数据
swap(c1,c2)置换数据

迭代器相关函数(Iterator Function)

c.begin()返回指向第一个元素的 bidirectional iterator
c.end()返回指向最末元素的 bidirectional iterator
c.cbegin()返回指向第一个元素的 const bidirectional iterator
c.cend()返回指向最末元素的 const bidirectional iterator
c.rbegin()返回反向指向第一个元素的 bidirectional iterator
c.rend()返回反向指向最末元素的 bidirectional iterator
c.crbegin()返回反向指向第一个元素的 const bidirectional iterator
c.crend()返回反向指向最末元素的 const bidirectional iterator

 Unordered 容器不允许直接元素访问,所以必须使用 range_based for循环或者iterator,由于 iterator 只保证是 forward iterator,不支持 bidirectional iterator 或 random-access iterator,因此在算法的选择上应该注意区分

对于 unordered set/multiset 而言, 它的 value 值是 const;对于 unordered map/multimap 而言,它的 key 是 const。这取决于 const 的值与 元素所在位置有关,除 hash function 之外不允许修改

 安插和移除函数(Inserting and Removing Element)

c.insert(val)安插一个 val 的拷贝,返回新元素位置
c.insert(pos,val)安插一个 val 的拷贝,返回新元素位置(pos是暗示起点)
c.insert(beg,end)将[beg,end)范围内的元素全部拷贝插入
c.insert(initlist)将初值列 中的元素全部拷贝插入
c.emplace(args...)安插一个以 args 为初值的元素,并返回新元素位置
c.empalce_hint(pos,args...)安插一个以 args 为初值的元素,并返回新元素位置,pos 是起点暗示
c.erase(val)移除所有 元素值等于 val 的元素,并返回移除个数
c.erase(pos)移除 iterator 为 pos 上的元素,无返回值
c.earse(beg,end)移除 iterator [beg,end)区间范围内的元素,无返回值
c.clear()移除所有元素

一般而言,erasing 函数并不会令指向元素的 iterator 和reference 失效,然而 insert 和 emplace 则可能使所有的 iterator 失效,但不会影响 reference 的有效性。所以 rehash 之所以发生是因为一次安插动作造成最终的元素数量个数大于等于 bucket 数量乘以最大负载系数

insert 和 earse 的差别:

Unordered set:
pair<iterator, bool> insert(const value_type& val);
iterator             insert(iterator posHint, const value_type& val);

template<typename... Args>
pair<iterator, bool> emplace(Args&&... args);
template<typename... Args>
interator            emplace_hint(const_interator posHint, Args&&... args);

Unordered multiset:
iterator             insert(const value_type& val);
iterator             insert(iterator posHint, const value_type& val);

template<typename... Args>
iterator             emplace(Args&&... args);
template<typename... Args>
interator            emplace_hint(const_interator posHint, Args&&... args);

由于 set(map一样)的元素的不可重复性,所以在插入时的返回是一个 pair 类型,first 时 元素 iterator,second 是是否成功插入

 Bucket 接口

c.bucket_count()返回当前 bucket 个数
c.bucket(val)返回 val 对应的 bucket 编号
c.bucket_size(buckidx)返回 第 buckidx 个 bucket 所含元素个数
c.begin(buckidx)返回一个 forward iterator,指向第 buckidx 个 bucket的第一元素
c.end(buckidx)返回一个 forward iterator,指向第 buckidx 个 bucket的最末元素
c.cbegin(buckidx)返回一个 const forward iterator,指向第 buckidx 个 bucket的第一元素
c.cend(buckidx)返回一个 const forward iterator,指向第 buckidx 个 bucket的最末元素

使用 Unordered Map 作为 Associative Array

c.[key]安插一个带 key 的元素——如果不存在的话,返回 reference 指向带着 key 的元素
c.at[key]返回一个 reference 指向带着 key 的元素

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值