STL hash_map 底层初探

来源:互联网 发布:剑灵人物捏脸数据下载 编辑:程序博客网 时间:2024/05/14 09:39

 hash_map 底层是采用hashtable实现的,在讲解hash_map之前,先看一下hash_table的原理。

(1)hashtable数据结构

hash table表格内的元素称为桶(bucket),而由桶所链接的元素称为节点(node),其中存入桶元素的容器为stl本身很重要的一种序列式容器——vector容器。之所以选择vector为存放桶元素的基础容器,主要是因为vector容器本身具有动态扩容能力,无需人工干预。而节点元素为自定义的结构体:

template<class Value>

struct __hashtable_node{   

    __hashtable_node* next;

    Value val;

};

可以看到,这本身就是一种很典型的链式列表元素的表示方法,通过当前节点,我们可以很方便地通过节点自身的next指针来获取下一链接节点元素。如下图:



(2)hashtable中的迭代器原理:

向前操作:首先尝试从目前所指的节点出发,前进一个位置(节点),由于节点被安置于list内,所以利用节点的next指针即可轻易完成前进操作,如果目前正巧是list的尾端,就跳至下一个bucket身上,那正是指向下一个list的头部节点。注意没有hahtable不存在反向迭代器

如下图:


从头到尾迭代器将依次输出: 53, 55, 2, 108, 59, 63  (和map,set不同,这里是无序输出)


(3)hashtable的扩充resize(...)方法

此api主要用于判断当前装载桶元素的vector容器是否需要重建(或者说是扩),api的唯一参数即为当前桶元素所链接所有节点个数,即链表节点个数(包括当前桶元素),假定为new_num。将new_num值与当前装载桶元素vector容器的大小进行比较,如果大于则进行容器扩容,依次将所有的节点元素都根据其本身的hash值放置到新的容器对应的桶元素所在的链表中。从上诉算法中我们可以看到每个桶元素所在的链表的元素个数最多为装载桶元素的vector容器的容量。。

(4) hash_map

了解了hashtable的原理,我们下面将下hash_map  。 hash_map 的直观实现如下:


hash_map每个节点中保存着一个key, 一个value 以及指向下一个节点的指针还有erased位。

(5) map 和hash_map之间的差别

map和hash_map之间最本质的差异就在于:map对其元素类型有一个 < , 而hash_map要求一个== 和一个散列函数。 (原因是map需要对元素进行排序,而hash_map不对元素排序)这样hash_map的非默认创建方式必然就与map不同。例如:
map<string, int> m1; // 用< 比较串
map<string, int , Nocase>m2 ; //用自定义的比较串
hash_map<string, int> hm1; // 用Hash<string>()散列,用==比较
hash_map<string, int, hfct> hm2; // 用hfct()散列,用==比较
hash_map<string, int , hfct, eql> hm3; // 用hfct()散列,用eql比较
(6)map和hash_map之间的权衡
       map之间的权衡应该是时间和空间的权衡。有效散列的关键在于散列函数的质量。如果无法找到一个好的散列函数,map就容易在性能上超过hash_map. 给予C风格字符串、string或者整数的散列通常都非常有效。
      如果要保持元素的顺序性,就选用map而不选用hash_map 如果
      如果查找速度极其重要,就选用hash_map而不是map.
      如果无法对元素定义小于操作时,选用hash_map而不是map。

(6)hash_map 使用

 参见:http://blog.csdn.net/sdhongjun/article/details/4517325

0 0