散列技术

来源:互联网 发布:网络黄页是什么 编辑:程序博客网 时间:2024/05/22 03:07

翻了一下数据结构的书,复习了散列的相关知识点,总结如下:

      散列方法的主要思想是根据结点的关键码值来确定其存储地址:以关键码值K为自变量,通过一定的函数关系h(K)计算出对应的函数值,把这个值解释为结点的存储地址,将结点存入到此存储单元中。在一般的情况下,散列表的空间必须比结点的集合大,此时虽然浪费了一定的空间,但是换取的是检索效率。散列的好坏依赖于散列函数的设计。散列函数可能对于不相等的关键码计算出相同的散列地址即发生冲突,发生冲突的两个关键码称为该散列函数的同义词。

       采用散列技术时候需要考虑的两个首要问题是:

       1)如何构造使结点“分布均匀”的散列函数?

       2)一旦发生冲突,用什么方法来解决?


 

散列函数

1. 除余法

    h(x)=x mod M

    通常M的值为某个质数或者2的幂

2. 乘余取整法

    hash(key)=floor(n*(A*key%1)); 

    A*key%1=A*key-floor(A*key)

    通常假设地址空间为p位,则n=power(2,p)。研究表明一般取A=(sqrt(5)-1)/2

3. 平方取中法

4. 数字分析法

5. 基数转换法

    将关键码值看成另一种进制的数再转换成原来进制的数,然后选其中几位作为散列地址。如key=210485,则

    21048513=2×135+1×134+0×133+4×132+8×13+5=77193210

    假设散列表长度为10000,则可去最低4位1932作为散列地址。通常要求两个基数互素,且新基数比原基数大

6. 折叠法

7. ELFhash字符串散列函数


 

解决冲突的方法

1. 开散列方法(拉链法)

     开散列方法的一种简单形式就是把散列表的每个槽定义为一个链表的表头。散列到一个特定槽的所有记录都放在这个槽的链表中。一个开地址的槽链接的线性表(同义词表)中的同义词记录可以按照多种方式排列:根据输入顺序、根据值的顺序或者根据访问频率的顺序。

2. 闭散列方法(开地址方法)

      闭散列表解决冲突的基本思想是当冲突发生时候,使用某种方法为关键码K生成一个散列地址序列d0,d1,...,dm-1。当插入K时候,若基地址已被别的数据元素占用,则按上述地址序列依次探查

2.1. 线性探查法

      将散列表看成一个环形表,若在基地址d(h(k)=d)发生冲突,则依次探查下述地址单元:d+1,d+2,...,M-1,0,1,...,d-1,直到找到一个空闲地址或者查找到关键码为key的结点为止。

2.2. 二次探查法

       二次探查法的基本思想是生成的后继散列地址不是连续的,而是跳跃式的,以便为后续数据元素留下空间减少聚集。二次探查法的探查序列依次为12,-12,22,-22,...

2.3. 随机探查法

       实际上不能随机地从探查序列中选择一个位置,因为在检索关键码的时候不能建立同样的探查序列。所以实际上应该是伪随机探查,即探查序列中的第i个槽是(h(K)+ri)mod M,其中ri是1到M-1之间数的随机数序列。

2.4.双散列探查法

      伪随机探查和二次探查都能消除基本聚集--即基地址不同的关键码,其探查序列的某些段重叠在一起的问题。然而,如果两个关键码散列到同一个基地址,那么采用这两种方法还是得到同样的探查序列,仍会产生聚集。这是因为伪随机探查法和二次探查法产生的探查序列只是基地址的函数,而不是原来关键码值的函数。这个问题成为二级聚集。

       为了避免二级聚集,需要时的探查序列是原来关键码值的函数,而不是基地址的函数。

       爽散列探查法使用两个散列函数h1和h2,其中h1和前面的h一样,以关键码为自变量,产生0到M-1之间的一个数作为散列地址,h2也以关键码为自变量产生一个1到M-1之间的、并与M互素的数作为对散列地址的补偿。

       双散列函数探查法下一个开放式的地址的公式为di=(d+ih2(key))%M

       通常选择M为一素数,h2返回值在[1,M-1]之间。另一种方法是设置M=2m,让h2返回一个1到2m-1之间的奇数值

       之所以两者要互素,是为了使发生冲突的同义词地址均匀地分布在整个表中,否则可能造成同义词地址的循环计算,从而在存储区并未放满时候就产生溢出。

原创粉丝点击