算法导论 开放寻址法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_26025363/article/details/64934515

散列表

11.4 开放寻址法

  1. 开放寻址法中,所有的元素都存放在散列表里,每个表项或包含动态集合的一个元素或者NIL。当查找某个元素时,要系统的检查所有表项,直到找到所有的元素或者最终查明元素不在表中。
  2. 为了使用开放寻址法插入一个元素,需要连续的检查散列表,或称为探查(probe),直到找到一个空槽来放置待插入的关键字为止。检查的顺序不一定是0,1,2…m的顺序序列,而是依赖于待插入的关键字。
  3. 将散列函数扩充,使之包含探查号,即 U(0,1,...,m1)(0,1,...,m1) ,对每一个关键字,使用开放寻址法的探查序列 ( h(k,0),h(k,1),…, h(k,m-1) )
  4. 该散列方法的思想在于:插入一个关键字k,如果k被占用,则往后一个位置插入, 直到没有空间。与链接法相比,不需要指针,所以可以将指针所占用的空间存放更多的槽。
  5. 缺点在于:该方法的删除操作,如果删除了某个关键字后,无法检索到以后的关键字了。如果用一个特定的值代替,查找时间就不依赖于转载因子 α 了。
  6. 定义一个均匀散列的假设:每个关键字的探查序列等可能的为0,1…,m-1中的m!中排列的一种。
  7. 三种技术用来计算探查序列:
    • 线性探查
      • 线性探查所用的散列函数为:h(k,i)=(h’(k)+i) mod m,i=0,1…,m-1
      • 问题:随着连续被占用的槽不断增加,平均查找时间也随之不断增加。
    • 二次探查
      • 采用如下的散列函数 h(k,i)=(h’(k)+i) mod m,i=0,1,…m-1
      • 问题:如果两个关键字的初始探查位置相同,那么它们的探查序列也是相同的。
    • 双重散列
      • 散列函数: h(k,i)=(h1(k)+ih2(k))%m
      • 这个函数的探查序列以两种不同方式依赖于关键字k。
  8. 定理:给定一个装载因子为 α=n/m<1 的开放寻址散列表,并假设其是均匀散列的,则对于一次不成功的查找,其期望的探查次数至多为1/(1- α )

练习

11.4-1

代码如下:

```
#include<stdio.h> 
//线性散列

int Linear_probing(int m,int key,int i)
{
return (key+i)%m;
}

//二次散列
int quadratic_probing(int m,int key,int i)
{
    return  (key+i+3*i*i)%m;
}

//多重散列
int double_hashing(int m,int key,int i)
{
    return (key+i*(1+key%(m-1)))%m;
}


//插入过程,其中有个函数指针,传递所需的散列函数
void  Insert(int a[],int (*func)(int ,int,int),int m,int key)
{
    int i=0;
    int x;

 do{
     x=func(m,key,i);
    if(a[x]==-1)
     {
           a[x]=key;
           return;
     }   
     else
         i++;
 }while(i!=m);
     printf("no slot to insert \n");
}

//搜索过程,用函数指针,传递散列函数
int Search(int a[],int (*func)(int,int,int) ,int m,int key)
{
    int i=0;
    int x=func(m,key,i);
    while(key!=a[x]&&i<m)
    {
        i++;
        x=func(m,key,i);
    }

    if(i==m)
    {
          return -1;
    }
    else
    {
        printf("%d\n",x);
          return x;
      }
}



int main()
{
    int m=11;
    int hash_Linear[11];
    int hash_Quad[11];
    int hash_Doub[11];
    int i;

    //列表初始化 
    for(i=0;i<11;i++)
        {
            hash_Linear[i]=-1;  //-1代表槽中没有元素
            hash_Quad[i]=-1;  //C语言初始化真坑,不能{}
            hash_Doub[i]=-1;  //挑了我半天bug!!
        }

    int b[9]={10,22,31,4,15,28,17,88,59};
    int j;
    for(j=0;j<9;j++)
    {
        Insert(hash_Linear,Linear_probing,11,b[j]);
        Insert(hash_Quad,quadratic_probing,11,b[j]);
        Insert(hash_Doub,double_hashing,11,b[j]);
    }

    for(j=0;j<11;j++)
    {
        printf("%d\t",hash_Linear[j]);
    }
    printf("\n");

    for(i=0;i<11;i++)
    {
        printf("%d\t",hash_Quad[i]);
    }
    printf("\n");
    for(i=0;i<11;i++)
    {
        printf("%d\t",hash_Doub[i]);
    }
    printf("\n");
    return 0;
}
```

11.4-2

  • 将上述插入代码的条件判断增加一个DELETED,可以用-2赋值为删除。

11.4-3

  • 根据书上公式,可得出

11.4-4

  • 先占坑,证明留待以后完成

11.5 完全散列

  • 当关键字为静态时,散列技术能提供出色的最佳情况性能。所谓静态,就是指一旦给定各关键字存入表中,关键字集合就不在变化了
  • 一种能在最坏情况下用O(1)访存完成的查找,是完全散列
  • 完全散列用两级的散列方法来设计
    • 第一级与带链接的散列表基本上是一样的,利用从某一全域散列函数簇中仔细挑选一个散列函数h,将n个关键字集合散列到m个槽中
    • 采用一个较小的二级散列表,为确保二级上不出现冲突,需要让散列表的大小为散列槽的平方个数

猜你喜欢

转载自blog.csdn.net/qq_26025363/article/details/64934515
今日推荐