STL 简单 hashtable 的实现

本文介绍了STL简单hashtable的实现,重点讨论了开链法解决碰撞问题,包括线性探测、二次探测和开链法的详细过程,并探讨了开链法的名称约定。此外,还涉及了hashtable的设计与实现,包括构造与析构、空间配置器、vector的使用以及hash_table节点和迭代器的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 简介

         Hash_table可提供对任何有名项(named item)的存取、删除和查询操作。由于操作对象是有名项,所以hash_table可被视为是一种字典结构(dictionary)。

         Hash_table使用名为hash faction的散列函数来定义有名项与存储地址之间的映射关系。使用hash faction会带来一个问题:不同的有名项可能被映射到相同的地址,这便是所谓的碰撞(collision)问题,解决碰撞问题的方法主要有三种:线性探测(linear probing)、二次探测(quadratic probing)、开链(separate chaining)。

 

1.1 线性探测

         先介绍一个名词:负载系数(loading factor),意为元素个数除以表格大小。负载系数永远在0 ~ 1之间(除非使用开链策略)。

         当hash faction计算出某个元素的插入位置,而该位置已经被占用时,我们循序往下查找,直到找到一个可用空间为止。然而这凸显了一个问题:平均插入成本的涨幅,远高于负载系数的涨幅。这样的现象在hashing过程中被称为主集团(primary clustering)。此时我们手上有一大团已经被占用的方格,插入操作极有可能在主集团所形成的泥泞中艰难爬行,不断碰撞,最后好不容易才找到一个落脚处,但这又助长了主集团的泥泞面积。

 

1.2 二次探测

         二次探测主要用来解决主集团的问题。如果hash faction计算出新元素的位置为H,但该位置被占用,那我们尝试H + 1^2、H + 2^2、H +3^2…..,而不是H + 1、H + 2、H + 3…….。二次探测可以消除主集团(primary clustering),但是可能造成次集团(secondary clustering)。

 

1.3 开链

         这是我们采用的方法。

         在每个表格元素中维护一个 list(链表),list 由 hash faction 为我们,我们在list上执行元素的插入、查找、删除等操作,虽然对list进行的查询是线性操作,但是 list 足够短的话,我们也能获得较好的效率。注意,使用开链法,表格的负载系数可能大于1。

 

1.4 开链法的名称约定

         下面介绍开链法中的基本术语,这些术语将贯穿博客和代码注释。

         我们用vector作为hash_table的底层实现,并称hash_table内的每个元素为桶子bucket,每个桶子里装着一个list头指针,通过list头指针,可以串联出一串节点(node)。这就是开链法的精髓:hash_table(底层是vector)的每个元素装着list头指针,每个list头指针可以开出一条链表。

Hash_table的实现方式有点像deque,关于deque的实现,请看另一篇博客:STL简单deque的实现


2.设计与实现

         我用VS2013写的程序(github),set和multiset版本的代码位于cghSTL/version/cghSTL-0.4.3.rar

 

在STL中,set和multiset的底层都需要以下几个文件:

1.    globalConstruct.h,构造和析构函数文件,位于cghSTL/allocator/cghAllocator/

2.    cghAlloc.h,空间配置器文件,位于cghSTL/allocator/cghAllocator/

3.    hash_table_node.h,hash_table节点的实现,位于cghSTL/associative containers/RB-tree/

4.    hash_table_iterator.h,hash_table迭代器的实现,位于cghSTL/associativecontainers/cgh_hash_table/

5.    cgh_hash_table.h,hash_table的实现,位于cghSTL/associativecontainers/cgh_hash_table/

6.    test_cgh_hash_table,测试文件,位于cghSTL

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值