`
ajuanlong
  • 浏览: 105390 次
社区版块
存档分类
最新评论

STL系列之九 探索hash_set

 
阅读更多

Title: STL系列之九 探索hash_set

Author: MoreWindows

Blog: http://blog.csdn.net/MoreWindows

E-mail: morewindows@126.com

KeyWord: C++ STL set hash_set 哈希表 链地址法

本文将着重探索hash_set比set快速高效的原因,阅读本文前,推荐先阅读本文的姊妹篇《STL系列之六 set与hash_set

一.hash_set之基石——哈希表

hash_set的底层数据结构是哈希表,因此要深入了解hash_set,必须先分析哈希表。哈希表是根据关键码值(Key-Value)而直接进行访问的数据结构,它用哈希函数处理数据得到关键码值,关键码值对应表中一个特定位置再由应该位置来访问记录,这样可以在时间复杂性度为O(1)内访问到数据。但是很有可能出现多个数据经哈希函数处理后得到同一个关键码——这就产生了冲突,解决冲突的方法也有很多,各大数据结构教材及考研辅导书上都会介绍大把方法。这里采用最方便最有效的一种——链地址法,当有冲突发生时将具同一关键码的数据组成一个链表。下图展示了链地址法的使用:

二.简化版的hash_table

按照上面的分析和图示,并参考《编程珠玑》第15章中哈希表的实现,不难写出一个简单的哈希表,我们称之为简化版hash_table。该哈希表由一个指针数组组成,数组中每个元素都是链表的表头指针,程序分为hash_table.h,hash_table.cpp和main.cpp。

1.hash_table.h

2.hash_table.cpp

3.main.cpp

在main.cpp中,对set、hash_set、简化版hash_table作一个性能测试,测试环境为Win7+VS2008的Release设置(下同)。

在数据量为500万时测试结果如下:

从程序运行结果可以发现,我们自己实现的hash_table(简化版)在插入和查找的效率要远高于set。为了进一步分析,最好能统计hash_table中的各个链表的长度情况,这样可以有效的了解平均每次查找要访问多少个数据。写出统计hash_table各链表长度的函数如下:

用此段代码得到链表长度的统计结果:

可以发现在hash_table中最长的链表也只有5个元素,长度为1和长度为2的链表中的数据占全部数据的89%以上。因此绝大数查询将仅仅访问哈希表1次到2次。这样的查询效率当然会比set(内部使用红黑树——类似于二叉平衡树)高的多。有了这个图示,无疑已经可以证明hash_set会比set快速高效了。但hash_set还可以动态的增加表的大小,因此我们再实现一个表大小可增加的hash_table。

三.强化版hash_table

首先来看看VS2008中hash_set是如何实现动态的增加表的大小,hash_set是在hash_set.h中声明的,在hash_set.h中可以发现hash_set是继承_Hash类的,hash_set本身并没有太多的代码,只是对_Hash作了进一步的封装,这种做法在STL中非常常见,如stack栈queue单向队列都是以deque双向队列作底层数据结构再加一层封装。

_Hash类的定义和实现都在xhash.h类中,微软对_Hash类的第一句注释如下——

hash table -- list with vector of iterators for quick access。

哈哈,这句话说的非常明白。这说明_Hash实际上就是由vector和list组成哈希表。再阅读下代码可以发现_Hash类增加空间由_Grow()函数完成,当空间不足时就倍增,并且表中原有数据都要重新计算hash值以确定新的位置。

知道了_Hash类是如何运作的,下面就来考虑如何实现强化版的hash_table。当然有二个地方还可以改进:

1._Hash类使用的list为双向链表,但在在哈希表中使用普通的单链表就可以了。因此使用STL中的vector再加入《STL系列之八 slist单链表》一文中的slist来实现强化版的hash_table。

2.在空间分配上使用了一个近似于倍增的素数表,最开始取第一个素数,当空间不足时就使用下一个素数。经过实际测试这种效果要比倍增法高效一些。

在这二个改进之上的强化版的hash_table代码如下:

下面再对set、hash_set、强化版hash_table的性能测试:

测试结果一(数据量500万):

测试结果二(数据量1千万):

测试结果三(数据量1千万):

可以看出,由于强化版hash_table的哈希表在增加表空间大小时会花费额外的一些时间,所以插入数据的用时与STL提供的hash_set用时相差不多了。但查找还是比hash_set要快的一些。

四.结语

从简化版到强化版的hash_table,我们不仅知道了hash_set底层数据结构——哈希表的运作机制,还知道了如何实现大小动态变化的哈希表。达到了本文让读者了解hash_set快速高效的原因。当然本文所给hash_table距真正的hash_set还有不小的距离,有兴趣的读者可以进一步改进。

此外,本文所示范的哈希表也与最近流行的NoSql数据库颇有渊源, NoSql数据库也是通过Key-Value方式来访问数据的(访问数据的方式上非常类似哈希表),其查找效率与传统的数据库相比也正如本文中hast_set与set的比较。正因为NoSql数据库在基础数据结构上的天然优势,所以它完全可以支持海量数据的查询修改且对操作性能要求很高场合如微博等。

转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/7330323

分享到:
评论

相关推荐

    stl_code.rar_STL vector_hash_stl set code_vector_vector stl

    c++ STL source code, hash and vector etc

    C++ STL 参考手册Cpp_STL_ReferenceManual.pdf

    STL 是“Standard Template Library”的缩写,中文译为“标准模板库”。...例如,vector 的底层为顺序表(数组),list 的底层为双向链表,deque 的底层为循环队列,set 的底层为红黑树,hash_set 的底层为哈希表。

    STL.源码剖析_____________

    源码之前了无秘密,你将看到vector的实现、list的实现、heap的实现、deque的实现、RB-tree的实现、hash-table的实现、set/map 的实现;你将看到各种算法(排序、搜寻、排列组合、数据移动与复制…)的实现;你甚至将...

    STL.zip_Map 排序_STL_Table_stl map实现

    源码之前了无秘密,你将看到vector的实现、list的实现、heap的实现、deque的实现、Red Black tree的实现、hash table的实现、set/map的实现;你将看到各种算法(排序、查找、排列组合、数据移动与复制技术)的实现;你...

    linked_hash:L链式哈希[LRU]用于C ++的快速,仅标头,跨平台和类似STL的linked_hash_map和linked_hash_set。 (在leetcode上击败100%的提交)

    linked_hash测试结果

    STL源码剖析_Table_stlmemory_c++prim_vector_

    STL源码剖析,这本书所呈现的源码,使读者看到vector的实现、list的实现、heap的实现、deque的实现、Red Black tree的实现、hash table的实现、set/map的实现;看到各种算法(排序、查找、排列组合、数据移动与复制...

    C++ STL开发技术导引(第5章)

    23.22 集合求异set_symmetric_difference 399 23.23 最小值min 401 23.24 最大值max 402 23.25 最小元素min_element 403 23.26 最大元素max_element 404 23.27 字典比较lexicographical_compare 405 23....

    细讲c++ 各种STL容器的应用场合及性能

    c++ std stl各容器的应用场合及性能 map hash_map unordered_map multimap list forward_list vector set hash_set multiset unsorted_set queue deque priority_queue

    C++ STL 开发技术导引(随书源码)

    本书共分5篇26章,以“C++编程技术→C++ STL泛化技术基础→C++ STL容器技术→C++ STL算法技术→C++ STL迭代器技术”为线索具体展开,通过大量的源码分析和应用实例,详细介绍了C++ STL的技术原理和使用方法。...

    C++ STL 开发技术导引(第6章)

    23.22 集合求异set_symmetric_difference 399 23.23 最小值min 401 23.24 最大值max 402 23.25 最小元素min_element 403 23.26 最大元素max_element 404 23.27 字典比较lexicographical_compare 405 23....

    STL源码剖析.pdg

    6.5.4 set_symmetric_difference 336 6.6 heap算法:make_heap, pop_heap, push_heap, sort_heap 338 6.7 其它算法 338 6.7.1 单纯的数据处理 338 adjacent_find 343 count 344 count_if 344 find 345 find_...

    STL 源码剖析(侯捷先生译著)

    6.5.4 set_symmetric_difference 336 6.6 heap算法:make_heap, pop_heap, push_heap, sort_heap 338 6.7 其它算法 338 6.7.1 单纯的数据处理 338 adjacent_find 343 count 344 count_if 344 find 345 find_...

    C++ STL开发技术导引(第3章)

    23.22 集合求异set_symmetric_difference 399 23.23 最小值min 401 23.24 最大值max 402 23.25 最小元素min_element 403 23.26 最大元素max_element 404 23.27 字典比较lexicographical_compare 405 23....

    Effictive STL CHM中文版

    》灰《《常好的STL教程Effective STL 目录 容器 条款1: 仔细选择你要的容器 条款2: 小心对“容器无关代码”的幻想 条款3: 使容器里对象的拷贝操作轻量而正确 条款4: 用empty来代替检查size是否为0 条款5: ...

    Analysis of STL Source Code

    这本书所呈现的源码,使读者看到vector的实现、list的实现、heap的实现、deque的实现、Red Black tree的实现、hash table的实现、set/map的实现;看到各种算法(排序、查找、排列组合、数据移动与复制技术)的实现;...

    STL源码剖析 电子版

    这本书所呈现的源码,使读者看到vector的实现、list的实现、heap的实现、deque的实现、Red Black tree的实现、hash table的实现、set/map的实现;看到各种算法(排序、查找、排列组合、数据移动与复制技术)的实现;...

    STL实现代码(SGI版本,侯捷 STL源码解析)

    源码之前了无秘密,你将看到vector的实现、list的实现、heap的实现、deque的实现、Red Black tree的实现、hash table的实现、set/map的实现;你将看到各种算法(排序、查找、排列组合、数据移动与复制技术)的实现;...

    STL源码剖析简体中文完整版(清晰扫描带目录).pdf

    这本书所呈现的源码,使读者看到vector的实现、list的实现、heap的实现、deque的实现、Red Black tree的实现、hash table的实现、set/map的实现;看到各种算法(排序、查找、排列组合、数据移动与复制技术)的实现...

    STL源码剖析

    侯捷 STL源码剖析:一本剖析下面内容的书籍:vector、list、heap、deque、red black tree、hash table、set、map等等

    标准模板库(STL)源码剖析

    源码之前了无秘密,你将看到vector的实现、list的实现、heap的实现、deque的实现、RB-tree的实现、hash-table的实现、set/map 的实现;你将看到各种算法(排序、搜寻、排列组合、数据移动与复制…)的实现;你甚至将...

Global site tag (gtag.js) - Google Analytics