STL之hash_table的底层实现

转载自:http://www.cnblogs.com/JackyTecblog/archive/2012/08/12/2634764.html

 

Hashtable在C++的STL里占据着比较重要的一席之地。其中的hash_set、hash_map、hash_multiset、hash_multimap四个关联容器都是以hashtable为底层实现方法(技巧)。应该说,上述的四个关联式容器提供的api都是对hashtable原生态api的高层封装,因为hashtable本身都提供了它们所需要的基础api。接下来,说说自己对hashtable实现技巧的理解和总结吧!

 

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

template<class Value>

struct __hashtable_node{   

    __hashtable_node* next;

    Value val;

};

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

 

    在hashtable的实现过程中,我们会认识到一个专有名词:负载系数(loading factor),意指元素个数除以表格大小。很显然,通过开链法,负载系数会大于1。同样在开链方法中,用于装载桶元素的vector容器大小恒定为一个质数大小,在具体实现中表现为28个从小到大的28个质数,如:53、97、193、389。。。等等。每次重新分配vector容器大小时,总是将新容器大小设定为第一个大于当前需要的新容器大小的质数值(上述28个质数中的其中一个)。接下来,我们来谈谈hashtable中几个比较重要的原生态api的实现原理吧。具体的实现技巧建议查看stl源码。

 

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

 

insert_unique_noresize(...)方法:此api主要用于往hashtable中插入新值,同时新值不允许重复,否则就不插入,立刻返回。事实上,在正式开始执行此方法之前,首先需要运行前一个api:resize()方法,确定vector容器是否需要重建。需要的话则执行,否则再是执行当前api。原理很简单,第一步,根据待插入的新值运行内置函数:bkt_num(new_value),此方法主要是用于确定当前新值归属于哪个桶元素所在的链表中,方便之后插入操作。获取其所在的桶元素之后,依次遍历当前桶元素所在的链表,检查是否有与待插入的新值重复的元素,如果有,则直接退出当前函数,如果没有,则将待插入的新值插入当前链表的头部,完成新值的插入过程。

 

insert_equal(...)方法与insert_unique_noresize()原理类似,唯一不同的地方只是可以插入重复值,即若发现相同值,则直接将待插入新值插入到当前节点的后面即可。否则仍然插入到当前链表的头部位置。探究到这里,想必大家都已经知道呢,hashtable内置的api实现方式并不是很复杂,无非主要是对链表的操作,比如查找、插入,删除等操作。

clear(...)函数实现方式也主要就是依次删除各个桶元素所在的链表中的节点元素即可。

 

    经过上述分析和总结,可以看到,虽然stl本身实现很复杂,但是其实里面真正的实现细节并非我们大多数人想像的那样不可理解,只要大家敢于跨出第一步(探究源码的第一步),相信离真像就会越来越近。最后,以《stl 源码剖析》一书前言的一句经典结束今天的hashtable的探索之旅吧!——源码之前,了无秘密!与大家共勉吧!

 

 

以下转载自:https://blog.csdn.net/wxwjiayou/article/details/61413665 

一:hashtable概述

 1.它的节点是hash table node(并不是listNode)。

 2.表格用的是vector,其大小是28个指数中最接近所要求的数。

 3.用开链法。

 4.其迭代器没有减操作,也没有逆向迭代器。

 5.重建表格:当元素个数>hashtable表格的大小时要求重建表格,重建表格是要将每一个元素重新进行hash,然后再delete掉oldhashtable的所有元素。

 6.对于不是整形的键值要进行数值化(对应的ascll码)再进行hash。

 7.不能处理 string double float等类型。

二:hashtable_set

  1.用hashtable实现,因hashtable中实现了所以操作,所以hash_set直接调用hashtable的方法即可。

  2.与set不同的是,set用的是红黑树实现,且会自动排序,二hash_set不能。

三:hash_map

   1.hashtable中提供了hash_map的所有操作,所以直接调用hashtable的操作即可。

   2.与map的不同是map用红黑树实现可以自动排序,而hash_map不可。

四:hash_multiset

  1.与hash_set不同的是其调用的是hashtable的insert_equal()而hash_set调用的是insert_unique()这样就决定了hash_multiset可以有重复元素。

五:hash_multimap

   1.与同hash_set与hash_multiset的区别。

 

 

以下为自己写的:

判断某个元素值落脚在哪一个桶里面,这就是哈希函数的责任。SGI把这个任务包装了一层,先交给bkt_num()函数,再由其函数调用hash function,得到一个可以进行取模运算的数值。(为什么要这么做?:因为有些元素无法直接拿来对hash_table的大小进行取模运算,例如字符串。。因此我们就需要做一些转换)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值