《STL源码剖析》读书笔记之关联式容器(2)

1.hashtable

     二叉搜索树具有对数平均时间的表现,但这样的表现构造在一个假设上:输入数据有足够的随机性。而hashtable在插入、删除、搜寻等操作上也具有“常数平均时间的表现”,而且这种表现是以统计为基础的,不依赖于输入的随机性。

     一个简单的hashtable的例子:

     如果元素是32bits而不是16bits,我们要准备的array就必须是4GB的。这就大的不切实际了。如何避免一个大的荒谬的数组呢?办法之一就是使用某种映射函数,将大数映射为小数。负责将某以元素映射为一个“大小可接受之索引”,这样的函数称为hash function(散列函数)。使用散列函数会导致多个元素映射到同一个位置,我们可以采用线性探测、二次探测开链等做法,解决冲突。

     STL的hash table采用的是开链的做法。即在每个表格单元中维护一个list,然后我们在那个list身上执行元素的插入、搜寻、删除等操作。

     下图为STL中的hash table的图形表述:


(1)hashtable的迭代器

     hashtable的迭代器是forward_iterator类型,它只有前进操作,没有后退操作。当前进时,它尝试着从当前节点出发,前进一个位置。如果节点被安置在list内,利用节点的next指针即可轻易达成前进操作。如果目前节点正在list的尾端,就调到下一个bucket上,指向下一个list的头节点。

(2)hashtable的数据结构


     虽然开链发并不要求表格大小必须为质数,但STL仍然以质数来设计表格大小,并且先将28个质数计算好,以备随时访问,同时提供一个函数,用来查询这28个质数之中,最接近给定数并大于给定数的质数。


(3)hashtable的构造与内存管理

     当我们构造一个拥有若干个节点的hash table时,会调用如下构造函数:



     当进行插入操作时,会首先判断需不需要扩充表格。当hashtable里面存储的元素个数大于bucket vector的size时,就表明需要扩充bucket vector,扩充时会扩充到下一个更大的质数(保证查询效率为O(1))。

     在不需要重建bucket vector的情况下插入新节点,需要调用insert_unique_noresize()函数。


     如果允许插入重复键值节点的话,则使用insert_equal()函数。

     如何判断元素落在哪个bucket上?这本来是hash function的责任,STL把这个任务包装了一层,交给了bkt_num()函数。这么做的原因是很多元素型别不能直接拿来对hashtable的大小进行模运算,这时我们需要做一些转换(比如char*)。


     hash()函数针对char,int,long等整数型别基本上不做处理,直接返回原值,但对于字符串类型,则会调用一个转换函数。

     由此可知,STL的hashtable无法处理上述所列类别之外的类别,例如string,double,float。欲处理这些类别,用户需要为它们定义hash function。


2.hash_set

     set是以RB-tree为底层实现机制。STL除set之外还提供了另外一种容器:hash_set,它提供的接口与set完全一样,只是它的是以hashtable为底层实现机制。需要特别注意的是,hashtable有一些无法处理的型别(string,double,float等,除非用户自己定义hash函数),hash_set同样无法处理。

     运用set,为的是能够根据键值快速的搜索元素。这一点,不管底层是RB-tree或是hashtable,都能达成任务。但如果底层是RB-tree,则set有自动排序的功能。而如果底层是hashtable,则不能实现自动排序。


3.hash_map

     hash_map是以RB-tree为底层实现的另一种map。运用map,为的是能够根据键值快速的搜索元素。这一点,不管底层是RB-tree或是hashtable,都能达成任务。但如果底层是RB-tree,则map有自动排序的功能。而如果底层是hashtable,则不能实现自动排序。


4.hash_multiset

     实现与hash_set基本一致,唯一的区别是set里允许有重复的元素,即往set里面插值的时候调用的是hashtable的insert_equal()而不是insert_unique()。


5.hash_multimap

     实现与hash_map基本一致,唯一的区别是map里允许有重复的元素,即往map里面插值的时候调用的是hashtable的insert_equal()而不是insert_unique()。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
侯捷的《STL剖析》是一本关于STL(标准模板库)的学习笔记。这本书深入解析了STL的实现原理和设计思路,对于理解STL的内部机制和使用方法非常有帮助。这些学习笔记记录了作者在学习侯捷的《STL标准库和泛型编程》课程时的心得和总结,对于理解STL码和进行泛型编程都具有指导意义。 这本书涉及了STL的各个模块,包括容器、迭代器、算法等,并解释了它们的实现原理和使用方法。通过学习这本书,你可以更好地理解STL的底层实现和使用技巧。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [STLSourceAnalysis:stl原始码剖析(侯捷)的学习笔记](https://download.csdn.net/download/weixin_42175776/16069622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [候捷老师STL剖析视频课程笔记](https://blog.csdn.net/weixin_46065476/article/details/125547869)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [侯捷——STL剖析 笔记](https://blog.csdn.net/weixin_45067603/article/details/122770539)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值