数据结构之散列表

来源:互联网 发布:淘宝站外推广怎么做 编辑:程序博客网 时间:2024/05/17 00:09

  • 散列表哈希表
    • 散列函数的构造方法
      • 数字关键词的散列构造函数
      • 字符串关键字的散列函数构造
    • 冲突处理方法
      • 开放定址法
        • 线性探测法Linear Probing
        • 平方探测法Quadratic Probing-二次探测
        • 双散列探测法Double
        • 再散列
      • 分离链接法

散列表(哈希表)

“散列(Hashing)”的基本思想是
(1) 以关键字key为自变量,通过一个确定的函数 h(散列函数),计算出对应的函数值h(key),作为数据对象的存储地址。
(2)可能不同的关键字会映射到同一个散列地址上,即h(keyi) = h(keyj)(当keyi ≠keyj),称为“冲突(Collision)”。—-需要某种冲突解决策略


散列函数的构造方法

一个“好”的散列函数一般应考虑下列两个因素:
1. 计算简单,以便提高转换速度;
2. 关键词对应的地址空间分布均匀,以尽量减少冲突。

数字关键词的散列构造函数

  1. 直接定址法
    取关键词的某个线性函数值为散列地址,即h(key) = a*key + b (a、 b为常数)

  2. 除留余数法
    散列函数为: h(key) = key mod p 这里,p=Tablesize,一般p取素数.

  3. 数字分析法
    分析数字关键字在各位上的变化情况,取比较随机的位作为散列地址。
    比如: 取11位手机号码key的后4位作为地址:
    散列函数为:h(key) = atoi(key+7) (char * key)
    hash1

  4. 折叠法
    把关键词分割成位数相同的几个部分,然后叠加
    如: 56793542
    hash2

  5. 平方取中法
    hash3

字符串关键字的散列函数构造

  1. ASCII码加和法
    h(key)=(key[i]) mod TableSize
    问题:冲突严重

  2. 前3个字符移位法
    h(key)=(key[0]*27^2+key[1]*27+key[2]) mod TableSize

  3. 移位法
    涉及关键词所有n个字符,并且分布得很好:
    h(key)=(n1i=0key[ni1]×32i) mod TableSize
    如何快速计算:
    h("abcde")='a'*32^4+'b'*32^3+'c'*32^2+'d'*32+'e'

代码:

Index Hash ( const char *Key, int TableSize ){    unsigned int h = 0; /* 散列函数值, 初始化为0 */    while ( *Key != ‘\0’) /* 位移映射 */    h = ( h << 5 ) + *Key++;    return h % TableSize;}

冲突处理方法

常用处理冲突的思路:
* 换个位置: 开放地址法
* 同一个位置的冲突对象组织在一起: 链地址法

开放定址法

一旦产生了冲突(该地址已有其它元素),就按某 种规则去寻
找另一空地址.
* 若发生了第 i 次冲突,试探的下一个地址将增加di, 基本公式是:
hi(key) = (h(key)+di) mod TableSize ( 1≤ i < TableSize )
* di决定了不同的解决冲突方案: 线性探测(di=i)、平方探测(di=±i2)、双散列(di=i×h2(key))。

线性探测法(Linear Probing)

  • 线性探测法: 以增量序列 1, 2, ……,(TableSize -1)循环试探下一个存储地址。
    例4

平方探测法(Quadratic Probing)-二次探测

  • 平方探测法: 以增量序列12122222q2q2且q ≤ |TableSize/2| 循环试探下一个存储地址。
    hash5
  • 是否有空间,平方探测(二次探测)就能找得到?
    hash6

    有定理显示:如果散列表长度TableSize是某个4k+3(k是正整数)形式的素数时, 平方探测法就可以探查到整个散列表空间。

  • 在开放地址散列表中, 删除操作要很小心。通常只能“懒惰删除” ,即需要增加一个“删除标记(Deleted)” ,而并不是真正删除它。以便查找时不会“断链”。其空间可以在下次插入时重用。

双散列探测法(Double)

双散列探测法: diih2(key)h2(key)是另一个散列函数。
探测序列成: h2(key)2h2(key)3h2(key), ……
对任意的key, h2(key)0
探测序列还应该保证所有的散列存储单元都应该能够被探测到。
选择以下形式有良好的效果:
h2(key)=p(keymodp)
其中: p < TableSize, p、 TableSize都是素数。

再散列

当散列表元素太多(即装填因子 α太大)时, 查找效率会下降;
实用最大装填因子一般取 0.5 <= α<= 0.85
当装填因子过大时,解决的方法是加倍扩大散列表,这个过程叫
做“再散列(Rehashing)”

分离链接法

将相应位置上冲突的所有关键词存储在同一个单链表中

原创粉丝点击