侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

RBTree

Red-Black tree(红黑树)是一种节点有特定颜色的平衡二叉搜索树(balanced binary search tree),其特点如下:

  • 节点有颜色,红黑色有关系(具体可自己搜索)
  • 拥有平衡二叉搜索树的所有性质
  • rb_tree提供遍历操作,按照正常规则遍历(++ite),能获得排序状态
  • 不应使用re_tree的ite改变元素值,因为元素有其严瑾的排列规则
  • rb_tree用两种插入操作:insert_unique()和insert_equal(),后者key可以重复
  • rb_tree节点拥有双向指针,因为要前后遍历
  • 将rb_tree的node的数据称为value,它包括key和data

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

rb_tree的实现

rb_tree只以三笔资料表现自己:

  • node_count 节点的个数
  • header 指向tree_node的指针,此node下一个节点为head
  • key_compare key大小的比较规则

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

rb_tree实际大小为12(1 + 4 + 4 = 9,找到最近的4的倍数为12)

  • KeyOfValue的函数实现

identity函数,它继承自unary_function,返回传入元素自身。

  • Compare的函数实现
    传入一个function object,其内部重载操作符"()".

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

Set/Multiset

Set/Multiset以rb_tree为底层结构,其特点如下:

  • set、multiset排序依据为key,且其value和key合一,value就是key
  • set的key必须唯一,其insert为rb_tree的insert_unique();multiset的key可以重复,其insert是rb_tree的insert_equal();

set的实现

set相当于一种适配器模式,其所有操作转移到底层容器t。

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

  • VC6中的set实现
    VC6中没有identity(),自己实现一个仿函数_Kfn;

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

Map/Multimap

Map/Multimap以rb_tree为底层结构,其特点如下:

  • Map、Multiset排序依据为key;
  • map的key必须唯一,其insert为rb_tree的insert_unique();multimap的key可以重复,其insert是rb_tree的insert_equal();
  • map将key_type设置为const,禁止用户修改key,允许用户修改data;
  • multimap不可使用[ ]做insertion

map的实现

底层调用rb_tree

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

  • VC6中的map实现
    VC6中没有select1st(),自己实现一个仿函数_Kfn;

HashTable

hashtable是使用hash function实现元素的散列放置。

hash table空间不足、元素冲突问题

将元素编号H对空间大小M取模,得到元素在hash table的位置。

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

  • separate chaining 链式解决冲突

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)
将发生冲突的元素使用链表进行串接

  • rehash的触动

当hash table的总元素个数大于bucket(用来装物体的篮子)的个数时,进行rehash操作,即将bucket的数量增大到下一个选定的质数大小M,重新计算该放到哪个篮子。

hash table在STL中的实现

hash table中的数据:

  • HashFcn:hash(object)
  • EqualKey: equals(object)
  • ExtractKey: get_key(object);此三个为函数对象, 总大小为3
  • __hashtable_node: node
  • vector buckets;vector含三根指针,大小12
  • size_t: num_elements;unsigned_int, 大小为4

hash table大小为20(19调整为20)

模板hashtable中需要传入的模板参数:

  • Value 一种组合类型,包含key和data
  • Key
  • HashFcn 将元素散列到hash table中编号的函数
  • ExtractKey 元素可能是pair,此函数用于萃取key
  • EqualKey 用于指定key怎样为相等的函数
  • Alloc

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

hash table的某种实现:

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

hash function、hash code

  • hash(函数对象)的特化

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

  • string对象的hash实现:没有特定方法,够乱够随机即可。

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

string为C++的字符串,stl对于此种对象没有实现hash;对于C的字符串char*,实现了hash。

  • modlus运算,取余

侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)

unordered容器

过了C++11,以hash开头的容器改名为unordered(不定序)。
unordered_set, unordered_map;unordered_multiset, unordered_multimap;也都相当适配器,底层以hash_table为容器,功能和以rb_tree为容器的set,map相同。
侯捷《STL源码剖析》 | 容器详解 RBTree 和 HashTable(史上最简明介绍)


更多精彩文章,欢迎关注公众号“Li的白日呓语”。