STL源码剖析学习十一:hashtable
2012-04-25 15:19
225 查看
二叉搜索树具有对数时间的搜索复杂度,但是这样的复杂度是再输入数据有足够的随机性的假设上
哈希表在插入删除搜索操作上也具有常数时间的表现,而且这种表现是以统计为基础,不需要依赖输入元素的随机性
hashtable提供对任何有名项的存取操作和删除操作,可以视为一种字典结构,
负载系数:元素个数除以表格大小,除非使用开链,负载系数永远在0,1之间
碰撞的解决方法:
线性探测:
当hash function计算出某个元素的插入位置,而在该位置上的空间已经不可用时,循序往下寻找,
如果到达尾端则绕到头部继续寻找,直到找到一个可用的空间为止。
只要表格足够大,肯定能找到一个位置存放数据。
进行元素搜索时,如果计算出来的位置上的元素与我们搜索的目标不符,就循序一一往下寻找,直到找出符合者或者遇上空格。
元素的删除必须使用惰性删除,就是只标记删除记号而不是真正删除,当哈希表重新整理时再实际删除。
带来的问题:可能存在主集团,有一大团用过的数据,操作很可能在主集团中反复搜索,不断解决碰撞问题,最后找到合适的位置,但是又助长了主集团的范围。
二次探测:主要用来解决主集团的问题
如果计算得的位置H已经被占用,就尝试H+i*i。
开链:在每个表格中维护一个list,hash function计算得到一个位置,然后再那个list上进行删除查找插入的操作。
此时表格的负载系数将大于1。
STL中的哈希表就是用这种做法。
hashtable的桶与节点:
表格内的每个单元,涵盖的不只是节点(元素),还可以是一个桶节点。
buckets的聚合体,是以vector完成,以便有动态扩充能力。
hashtable的迭代器:
迭代器只有++没有--操作,也没有逆向迭代器。
hashtable的数据结构
template<class value, 节点的实值类别
class key, 节点的键值类别
class HashFcn, hash function函数类别
class ExtractKey, 从节点中取出键值的方法
class EqualKey, 判断键值相同与否的方法
class Alloc> 空间配置器,默认使用std::alloc
hashtable的插入与表格重整:
判断是否需要重建,如果不需要则返回,如果需要则重建
不需要重建的情况下插入
如果允许相同元素存在,则调用
查找
统计
hash function
计算元素的位置,SGI将这项任务先给了bkt_num(),然后再由它调用hash function,取得一个可以对hashtable进行模运算的值
对于char int long 都只是忠实的返回原值
const char *设计一个转换函数
for(;*s;++s)
h=5*h+*s
而对于string double float都必须由用户来定义hash function
hash_set
由于hash_set所供应的操作接口hashtable都提供了,所以几乎所有的hash_set操作行为,都只是转调用hashtable的操作行为而已
hash_set没有自动排序功能
使用方式和set完全相同
其余的hash_map hash_multimap hash_multiset用法和其对应的非hash的版本相同。
哈希表在插入删除搜索操作上也具有常数时间的表现,而且这种表现是以统计为基础,不需要依赖输入元素的随机性
hashtable提供对任何有名项的存取操作和删除操作,可以视为一种字典结构,
负载系数:元素个数除以表格大小,除非使用开链,负载系数永远在0,1之间
碰撞的解决方法:
线性探测:
当hash function计算出某个元素的插入位置,而在该位置上的空间已经不可用时,循序往下寻找,
如果到达尾端则绕到头部继续寻找,直到找到一个可用的空间为止。
只要表格足够大,肯定能找到一个位置存放数据。
进行元素搜索时,如果计算出来的位置上的元素与我们搜索的目标不符,就循序一一往下寻找,直到找出符合者或者遇上空格。
元素的删除必须使用惰性删除,就是只标记删除记号而不是真正删除,当哈希表重新整理时再实际删除。
带来的问题:可能存在主集团,有一大团用过的数据,操作很可能在主集团中反复搜索,不断解决碰撞问题,最后找到合适的位置,但是又助长了主集团的范围。
二次探测:主要用来解决主集团的问题
如果计算得的位置H已经被占用,就尝试H+i*i。
开链:在每个表格中维护一个list,hash function计算得到一个位置,然后再那个list上进行删除查找插入的操作。
此时表格的负载系数将大于1。
STL中的哈希表就是用这种做法。
hashtable的桶与节点:
表格内的每个单元,涵盖的不只是节点(元素),还可以是一个桶节点。
hash table的节点定义: template <class value> struct __hashtable_node { __hashtable_node* next; value val; }
buckets的聚合体,是以vector完成,以便有动态扩充能力。
hashtable的迭代器:
迭代器只有++没有--操作,也没有逆向迭代器。
operator++() { 检查当前节点的下一个节点 如果存在就是它 如果不存在则寻找下一个bucket 取下一个bucket的第一个元素 }
hashtable的数据结构
template<class value, 节点的实值类别
class key, 节点的键值类别
class HashFcn, hash function函数类别
class ExtractKey, 从节点中取出键值的方法
class EqualKey, 判断键值相同与否的方法
class Alloc> 空间配置器,默认使用std::alloc
hashtable的插入与表格重整:
insert_unique(const value_type& obj)//不允许元素重复的插入 { resize(num_elements+1);//判断是否需要重整表格 return insert_unique_noresize(obj); }
判断是否需要重建,如果不需要则返回,如果需要则重建
resize() { 判断表格是否需要重建:拿元素个数和bucket vector的大小来比,如果前者比后者大就重整 (因此,每个bucket(list)的大小和bucket vector的大小相同 如果要重建,则找出下一个质数作为vector的大小,建立新的buckets 处理每一个旧的bucket{ 建立一个新的节点指向节点所指的串行的起始节点 处理每一个旧bucket所含串行的每一个节点{ 找出节点落在哪一个新的bucket内 令旧bucket指向其所指的串行的下一个节点 将当前节点插入到新的bucket内,成为其串行的第一个节点 回到旧bucket所指的待处理串行,准备处理下一个节点 } } 新旧两个buckets对调,如果双方大小不同,大的会变小,小的会变大 离开时释放temp的内存 }
不需要重建的情况下插入
insert_unique_noresize() { 计算出obj应该位于哪个bucket 令first指向bucket对应的串行的头部 如果bucket已经被占用,检查整个链表 如果发现链表中有相同的元素,就立即返回 产生新节点,令新节点为链表的第一个节点,节点个数加一 }
如果允许相同元素存在,则调用
insert_equal_noresize() { 计算obj应该位于哪个bucket 令first指向bucket对应的串行的头部 如果bucket已经被占用,检查整个链表 如果发现链表中有相同元素,则产生新节点,插入目前节点之后,节点数加一 返回一个迭代器,指向新节点 进行到这里说明没有发现新节点 产生新节点 将新节点插入到链表的头部,节点个数加一 返回一个迭代器,指向新节点 }
查找
find() { 计算obj应该位于哪个bucket 从头部开始,一一对比每个元素的键值,比对成功就返回 }
统计
count() { 计算obj应该位于哪个bucket 从bucket list的头开始,一一对比每个元素的键值,对比成功就加一 }
hash function
计算元素的位置,SGI将这项任务先给了bkt_num(),然后再由它调用hash function,取得一个可以对hashtable进行模运算的值
对于char int long 都只是忠实的返回原值
const char *设计一个转换函数
for(;*s;++s)
h=5*h+*s
而对于string double float都必须由用户来定义hash function
hash_set
由于hash_set所供应的操作接口hashtable都提供了,所以几乎所有的hash_set操作行为,都只是转调用hashtable的操作行为而已
hash_set没有自动排序功能
使用方式和set完全相同
其余的hash_map hash_multimap hash_multiset用法和其对应的非hash的版本相同。
相关文章推荐
- STL源码剖析学习之容器
- STL源码剖析学习之数值算法
- STL源码剖析——hashtable
- STL源码剖析学习之基本算法
- STL源码剖析学习十四:算法之set相关算法
- STL源码剖析-学习之路(二)配置器
- STL源码剖析-关联式容器之hashtable
- STL源码剖析学习十九:配接器
- STL源码剖析——stl_pair.h学习
- STL源码剖析-学习之路(四)容器
- STL源码剖析-学习笔记
- Java集合框架学习(十一) Hashtable详解
- stl源码剖析 详细学习笔记priority_queue slist
- STL源码剖析学习十九:配接器
- STL源码剖析 学习笔记 MiniSTL
- stl源码剖析 详细学习笔记priority_queue slist
- STL源码剖析之哈希表 hashtable【2013.12.06】
- STL源码剖析学习八:heap & priority queue
- STL源码剖析学习九:树
- STL源码剖析-学习之路(五)仿函数