动态hash算法实现

动态hash算法实现

一、概述

       传统hash表的实现主要有拉链法和开放地址散列法,而开放地址散列法又包括线性散列、二次散列等。当插入hash表的元素不断增加时,传统hash表为保证查找效率,需要执行扩容然后对于hash表中的元素重新映射完成迁移。这项工作的开销往往比较大,故在这种场景下,可以适用动态hash算法。

二、动态hash原理

         动态hash的原理如下图所示,hash表大小为1<<table_prefix,每个hash表项指向一个block,每个block用于存放元素,其带有一个block_prefix,如果table_prefix== block_prefix,则只有一个表项指向这个block,否则指向block的表项数目为1 << (table_prefix - block_prefix)。

         在hash表扩容方面,动态hash优越于传统hash的地方在于动态hash表的元素迁移只会涉及到某一个block上的元素,其他block上的元素不用迁移。在原理上,hash函数值为固定位数(32位或64位),其利用hash函数值的后table_prefix位来决定元素存放的block号。在table扩容的过程中,对称表项指向相同的block,这样具有相同后缀hash函数值的元素会映射到同一个block上。

         当某一个block上的元素达到设定的上限数目时,再次向此block插入元素会导致hash表扩容,动态hash表扩容的场景可分为两类:

         一、只有一个表项指向这个block,此时table_prefix== block_prefix。这时需要针对table扩容,即table_prefix++,table的大小加倍。然后对称表项指向相同的block,需要插入元素的block进行元素迁移,也就是因为现在table_prefix比原来要大,元素分配block更精确了。这样原先block上会腾出空位,放入新插入的元素即可。需要迁移的元素另外组成一个block,让对称的表项指向新的block,相应地,由于指向block的表项数减少了,block_prefix也要增加,即block_prefix++。但是可能存在元素都不会迁移的场景,也就是说这时block中所有元素的后table_prefix位还是相同的。这时分两种情况,一是如果所有元素的hash函数值都相同,那么通过扩容增加table的大小是无济于事的,因为它们始终映射到同一个block,这时就需要在原先block的基础上增加一个溢出桶用来存放新插入的元素。二是此时的table_prefix还不够大,需要进一步加大table_prefix判断元素迁移的block号,这种情况就需要重复上述步骤。

         二、多个表项同时指向这个block,此时table_prefix> block_prefix。这时还不需要进行扩容,只需要进行元素迁移,迁移过程与情况一相同。


三、动态hash设计

         针对上述hash原理,设计出的hash表结构图如图所示,每个block会有一个item_t表项来记录block的相关信息,ref_count为引用计数,用来标识指向block的表项数目,控制block元素的释放,block带有next指针用于标识溢出桶。item中的hash_prefix就是上面说的block_prefix,table中的hash_prefix就是上面说的table_prefix。


         整个hash表操作涉及到插入、删除、查找,具体函数的实现见源代码。

四、接口使用说明

dhash_t*dhash_init(int block_len)

初始化构造dhash_t结构体,用于表示动态hash表,初始化成功返回dhash_t实例,否则返回NULL。

 

voiddhash_destroy(dhash_t *dhash)

销毁动态hash表,释放hash表内存,执行一些清理工作。

 

voidset_hash_func(dhash_t *dhash, hash_func_t func)

voidset_free_elem_func(dhash_t *dhash, free_elem_func_t func)

voidset_elem_equal_func(dhash_t *dhash, elem_equal_func_t func)

voidset_copy_elem_func(dhash_t *dhash, copy_elem_func_t func)

voidset_show_elem_func(dhash_t *dhash, show_elem_func_t func)

分别为动态hash表设置hash函数指针、元素释放指针、判断元素相等函数指针、拷贝元素函数指针、打印hash表函数指针。

 

elem_t*dhash_query(dhash_t *dhash, elem_t elem)

在hash表中查找指定元素,存在则返回元素指针,否则返回NULL。

 

intdhash_insert(dhash_t *dhash, elem_t elem)

在hash表中插入指定元素,成功返回0,否则返回-1。

 

intdhash_delete(dhash_t *dhash, elem_t elem)

在hash表中删除指定元素,成功返回0,否则返回-1。

 

voiddhash_show(dhash_t *dhash)

打印hash表中所有的元素。

五、源码

Talk is cheap, show me the code。动态hash算法的C实现源码已托管至github,见

https://github.com/xhjcehust/dynamic_hash,如果觉得还不错的话,fork和star是对作者写作的最大支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值