数据结构之hashtable
来源:互联网 发布:加热脚垫淘宝 编辑:程序博客网 时间:2024/05/20 20:19
1、基本概念
hashtable是一种存储成对的键值和实值元素的字典结构。不同于红黑树的对数级的平均时间消耗,hashtable提供常数级的时间消耗。
2、散列函数
为了达到常数级的时间消耗,底层必须使用array这种连续空间的内存结构。想要存储元素,就需要将元素的键值映射成对应的索引值,实现这种功能的映射函数就称为散列函数(hash function)。散列函数的实现是很重要的,不仅影响着存储array的大小,还决定着存储array利用率等很多东西。
3、元素碰撞
使用散列函数将元素的键值映射到一定区域内的索引位置,不可避免会出现不同的的键值得到相同的索引位置,这种情况就称为元素碰撞。当发生碰撞时,就需要采取一定的策略解决碰撞问题。
3.1线性探测。
当发生元素碰撞时,循环向下一个位置进行查找,到达尾端就跳转到头部继续查找,直到找到一个可以插入的空余位置。只要array够大,必然可以找到一个插入位置,但花费的时间就很难计算了。同理,在查找元素时也可能会花费大量的时间。同时,在碰撞发生后占用了碰撞位置附件其他元素的位置,导致这一区域的碰撞概率大大增加,从而形成恶性循环,我们称这种情况为主集团(primary cloustering)。
3.2平方探测。
为了解决主集团问题,我们在元素碰撞发生后,第1次移动一个位置,第2次移动4个位置,以此类推。由于是平方探测,为了保证必然可以找到一个插入位置,我们必须设定array的大小为质数。当保证负载系数在0.5以下时,没插入一个新元素的探测次数不超过两次。
相对于线性探测,平方探测的计算消耗更加大,但我们可以对这一消耗进行优化。已知H(i)=H(0)+i*i(mod M),H(i-1)=H(0)+(i-1)*(i-1)(mod M),可得H(i)=H(i-1) + (2i -1)(mod M),通过上一个位置可快速计算出下一个查找位置。
当负载系数超过0.5时,我们需要找出下一个新的且足够大的质数,对array进行扩充。此时并不是直接拷贝,而是扫描原有array内的元素,将其重新映射到新的array内。
平方探测解决了主集团问题,但一样会造成某些区域的碰撞概率较高,从而形成次集团(secondary cloustering)。
3.3双散列
为了解决次集团,我们在元素碰撞发生后,使用另一个散列函数查找插入位置。第二个散列函数的选择至关重要,最好能保证所有的位置都可被探测到。当相对于平方探测,散列函数的计算是更加耗时,因而需要根据不同的情况进行具体的选择。
3.4开链
不同于前面的散列方法,开链的做法是将相同散列值的元素放到同一个list里,这样完全避免了碰撞的问题,但由于使用了链表进行元素的存储,需要花费一些额外的空间。使用开链,array的负载系数将大于1,对于空间的利用率更高。标准STL就是使用这一方法实现的hashtable。
4、实际应用
hash_set和hash_map不属于标准库,但很多版本的STL都实现散列的版本,以下是测试用例:
hash_set<int> set;set.insert(3);set.insert(196);set.insert(1);set.insert(389);set.insert(194);set.insert(387);hash_set<int>::iterator iter1 = set.begin();hash_set<int>::iterator iter2 = set.end();for (;iter1 != iter2;++iter1){ cout<<*iter1<<" "; //3 387 196 1 389 194}cout<<endl;
这里需要注意的,由于hashtable的限制,有些数据类型是无法处理的,对应的hash_map也是无法处理的。例如设置类型为const char*时,不能使用缺省的equal_to(T),需要自己定义比较函数和哈希函数,以下为测试代码:
struct eqstr{ enum { // parameters for hash table bucket_size = 4, // 0 < bucket_size min_buckets = 8 // min_buckets = 2 ^^ N, 0 < N }; size_t operator()(const char* str) const { unsigned long h = 0; for (;*str;++str) { h = 5*h + *str; } return size_t(h); } bool operator()(const char* str1,const char* str2) const { return strcmp(str1,str2) == 0; }};typedef hash_map<const char*,int,eqstr> StrHashMap;StrHashMap map2;map2["a"] = 1;map2["b"] = 3;map2["c"] = 7;map2["d"] = 4;StrHashMap::iterator iter5 = map2.begin();StrHashMap::iterator iter6 = map2.end();for (;iter5 != iter6;++iter5){ cout<<(*iter5).first<<" "<<(*iter5).second<<endl; /*a 1 b 3 c 7 d 4*/}cout<<endl;
- 数据结构之hashtable
- 数据结构之Hashtable
- 数据结构探险之HashMap 与Hashtable
- Java 数据结构之 Hashtable(mark)
- java数据结构之散列集HashSet与散列表Hashtable
- 数据结构是哈希表(hashTable)
- Java 数据结构 --> Hashtable 接口
- 数据结构是哈希表(hashTable)
- 数据结构-HashTable的简单
- 数据结构—Hashtable(闭散列)
- 【数据结构】:哈希表(hashtable)
- 数据结构 hashtable C++实现 链式
- 数据结构-HashMap Hashtable HashSet
- Java数据结构源码分析-HashTable
- 数据结构大总结系列之从HASH谈到set/map再到hashtable/hash_map/hash_set
- 数据结构之HashTable(除留余数法—链地址法)
- 数据结构与算法分析之哈希表(HashTable,又称散列表)--理论篇
- 数据结构与算法分析之哈希表(HashTable,又称散列表)--代码篇
- chapter2- 概率模型限制条件
- Android之判断手机连接的网络类型是WIFI还是2G/3G/4G
- 大白话解释模型产生过拟合的原因
- 关于STM32F4将数据或文件写入W28Q128(SPI_FLASH)中的方法(精)
- wchar_t*和string相互转换
- 数据结构之hashtable
- Android中判断网络是否可用的代码
- Android程序检测网络是否可用
- 别再让这些老问题影响你求职了!
- 【HTML/JS】Javascript定义类(class)的三种方法
- Ext Js入门第2篇-核心工具方法
- js导出excel
- 图像预处理|直方图均衡
- io流