哈希查找

来源:互联网 发布:免费摄像头监控软件 编辑:程序博客网 时间:2024/05/02 08:39

1.哈希表的概念:

        哈希是一种重要的存储方法,也是一种重要的查找方法。
        基本思想:以关键字K为自变量,通过一个确定的函数f,计算出对应的函数值f (k),把这个值解释为关键字等于K的结点的存储地址。查找时,再根据要查找的关键字用同样的函数计算地址,然后到相应的存储单元取出要查找的结点。按这个思想建立的表,称为哈希表,称函数f 为哈希函数,称f (k)的值为哈希地址。

2. 哈希函数的构造方法: 

   2.1 直接定址法:

        取关键字或关键字的某个线性函数值为哈希地址。即: H(key) = key 或 H(key) = a*key+b 直接定址法由于关键字与存储地址存在一一对应关系,因此,不会 发生冲突现象。

   2.2 求模法:

        选择一个适当的正整数P(P≤表长),用P 去除关键字,取所得余数作为哈希地址。即:H(key) = key % P (P ≤ 表长) 求模法的关键是选取适当的P,一般选P为小于或等于哈希表的长 度m的某个素数为好。

   2.3 平方取中法:

        取关键字平方后的中间几位为哈希地址。由于一个数的平方的中间几位与这个数的每一位都有关,因而,平方取中法产生冲突的机会相对较小。平方取中法中所取的位数由表长决定。

   2.4 折叠法:

        把一个关键码分成位数相同的几段(最后一段的位数可以, 不同),段的长度取决于哈希表的地址位数,然后将各段的 叠加和(舍去进位)作为哈希地址。折叠法又分为移位叠加和边界叠加两种。其中,移位叠加是将 各段的最低位对齐,然后相加;而边界叠加则是两个相邻的段沿边界来回折叠,然后对齐相加。

   2.5 数字分析法:

        假设关键字是以r为基的数,并且哈希表中可能 出现的关键字都是事先知道的,则可取关键字中的若干位组成哈希地址。

3. 处理冲突的方法:

 3.1 开放定址法:

          基本做法:当冲突发生时,使用某种方法在哈希表中形成一探查序列,然后沿着此探查序列逐个单元地查找,直到碰到一个开放的地址(即该地址单元为空)为止。在哈希表中形成一探查序列时,可有三种不同的方法:

     ⑴ 线性探测法:

     基本思想:将散列看成是一个环形表,探测序列是(假设表长为m):
                         H(k),H(k)+1,H(k)+2,…,m-1,0,1,…,H(k)-1
     用线性探法解决冲突时,求下一个开放地址的公式为:
                         Hi = (H(k)+i) MOD m 

     ⑵ 二次探测法:

    二次探测法的探测序列依次是12,-12,22,-22,…等,当发生冲突时,求下一个开放地址的公式为: 
            H2i-1 = (H(k)+i2) MOD m
            H2i = (H(k)-i2) MOD m (1=< i <= (m-1)/2 )
    优点:减少了堆集发生的可能性。
    缺点:不容易探测到整个哈希表空间。

    ⑶ 伪随机探测法:

    采用随机探查法解决冲突时,求下一个开放地址的公式为:
       Hi = (H(k)+Ri) MOD m
   其中:R1,R2,…,Rm-1是1,2,…,m-1的一个随机排列。如何得随机排列,涉及到随机数的产生问题。

   3.2 再哈希法:

    基本做法:当冲突发生时,使用另一个哈希函数计算得到一个新的哈希地址,直到冲突不再发生时为止,即Hi = RHi(key) ,i = 1,2,…,k,其中,RHi均是不同的哈希函数。
    这种方法的优点是不易产生"堆集",但缺点是增加了计算时间。

   3.3 链地址法:

   基本做法:将所有关键字为同义词的结点链接在同一个单链表中。若选定的哈希函数所产生的哈希地址为0~m-1,则可将哈希表定义成一个由m个链表头指针组成的指针数组。

   这种方法的优点是:
    ① 不产生"堆集"。
    ② 由于结点空间是动态申请的,故更适合于造表前无法确定表长的情况。
    ③ 从表中删除结点容易。

   3.4 公共溢出区法法:

        基本做法:假设哈希函数的值域为[0..m-1],则设向量HashTable[0..m-1]为基本表,每个分量存放一个记录,另设立向量OverTable[0..v]为溢出表。所有关键字和基本表中关键字为同义词的记录,不管它们由哈希函数得到的哈希地址是什么,一旦发生冲突,都被填入溢出表中。

采用求模法和开放定址法的实例如下:

#include<iostream>using namespace std;int b[11];int H(int k){return k % 11;}void HashBuild(int a[],int n){int j,i;for (i = 0; i < n; i++){j = H(a[i]);while (b[j]){j = H(j + 1);}b[j] = a[i];}}int Search(int k){int i = H(k);while (b[i]){if (b[i] == k)return 1;i = H(i + 1);}return 0;}int main(){int a[] = {47,7,29,11,16,92,22,8,3};HashBuild(a,9);if (Search(7))printf("Find it!\n\n");elseprintf("Not Find!\n\n");return 0;}


原创粉丝点击