浅学cuckoo hash

  • 定义:
    CuckooHash(布谷鸟散列)是为了解决哈希冲突问题而提出,利用较少的计算换取较大的空间。
    • 特点:
      占用空间少,查询速度快。
    • 来源:
      之所以起这个名字是因为布谷鸟生性贪婪,不自己筑巢,而是在别的鸟巢里面鸟蛋孵化,先成长的幼鸟会将别的鸟蛋挤出,这样独享“母爱”,类似于哈希冲突处理过程
      • 算法描述:

      使用hashA、hashB计算对应的key位置:

      1、两个位置均为空,则任选一个插入;
      2、两个位置中一个为空,则插入到空的那个位置
      3、两个位置均不为空,则踢出一个位置后插入,被踢出的对调用该算法,再执行该算法找其另一个位置,循环直到插入成功。
      4、如果被踢出的次数达到一定的阈值,则认为hash表已满,并进行重新哈希rehash

      优化(减少哈希碰撞):

      1、将一维改成多维,使用桶(bucket)的4路槽位(slot);
      2、一个key对应多个value;
      3、增加哈希函数,从两个增加到多个;
      4、增加哈希表,类似于第一种;

      cuckoo hash代码题目:
      题目描述
      整数哈希表是一种数据结构,支持在常量时间内插入,删除和查找整数值。传统的哈希结构由一些大小为n的数组(哈希表)和一个通常为f(x)= x mod n的哈希函数f(x)组成。为了在表中插入一个值x,你计算它的散列值f(x),它作为存储x的位置的哈希表中的索引。例如,如果x = 1234并且散列表具有大小101,则1234将被存储在位置22 = 1234 mod 101中。当然,可能的是其他一些值已经存储在位置22中(例如,x = 22) ,这会导致碰撞。可以通过多种方式处理碰撞,您可以在比赛回家的路上与您的教员顾问讨论。
      杜鹃散列是一种散列形式,它使用两个散列表T1和T2,每个散列表都有自己的散列函数f1(x)和f2(x)。插入值x的过程如下:首先尝试使用f1(x)将x存储在T1中。如果该位置是空的,那么只需将x存储并完成。否则会发生必须处理的碰撞。设y是该位置当前的值。在T1中用x替换y,然后尝试使用f2(y)将y存储在T2中。再说一遍,如果这个位置是空的,你就在那里存储,你就完成了。否则,用y替换那里的值(称为z),然后尝试使用f1(z)将z存回T1中,依此类推。这个过程继续,在两张桌子之间来回跳动,直到你找到一个空的位置,或者直到有一定数量的掉期发生,此时你重新组合了这两张桌子(再次与你的教员顾问讨论)。出于这个问题的目的,后一种情况永远不会发生,即,该过程应该一直持续到找到一个空位置,这将保证每个插入的值发生。
      鉴于两个表的大小和一系列插入,您的工作是确定每个表中存储的内容。
      (对于那些有兴趣的人来说,杜鹃哈希的名字取决于杜鹃鸟的行为,该杜鹃鸟已知其他鸟类的巢穴,并将其自己的卵子与已经存在的鸡蛋一起放入其中。当较大的杜鹃小鸡孵化时,它会推动其他小鸡从巢中出来,从而得到所有的食物。可怕但有效。)
      输入
      每个测试用例的输入以3个正整数n1 n2 m开始,其中n1和n2是表T1和T2的大小(n1,n2≤1000和n1 6 = n2),m是插入的数量。接下来是m个整数值,它是要插入表中的值。所有这些值都是非负的。每个表最初是空的,表Ti使用散列函数fi(x)= x mod ni。包含3个零的行将终止输入。
      输出
      对于每个测试用例,在T1中输出非空位置,然后在T2中输出非空位置。对每个这样的位置和形式i:v使用一行,其中i是表的索引位置,v是存储在那里的值。每个表中的输出值从最低索引到最高。如果任一表为空,则不为该表输出任何内容。
    • 样例输入

      5 7 4
      8 18 29 4
      6 7 4
      8 18 29 4
      1000 999 2
      1000
      2000
      0 0 0
      

      样例输出

      Case 1:
      Table 1
      3:8
      4:4
      Table 2
      1:29
      4:18
      Case 2:
      Table 1
      0:18
      2:8
      4:4
      5:29
      Case 3:
      Table 1
      0:2000
      Table 2
      1:1000

      代码实现:

    • #include <iostream>
      #include <cstdio>
      #include <cstring>
       
      using namespace std;
       
      int main()
      {
          int n1,n2,m;
          int a[1000];
          int b=1;
          int bq=1;
          int h1[1005];
          int h2[1005];
          int cc=0;
          while(scanf("%d %d %d",&n1,&n2,&m)!=EOF&&m!=0){
              b=1;
              bq=1;
              memset(h1,0,sizeof(h1));
              memset(h2,0,sizeof(h2));
              for(int i=0;i<m;i++){
                  scanf("%d",&a[i]);
              }
              for(i=0;i<m;i++){
                  int locat=a[i]%n1;
                  int locat2=a[i]%n2;
                  if(b==1 && h1[locat]!=0){
                      int t=h1[locat];
                      h1[locat]=a[i];
                      a[i]=t;
                      i--;
                      b=2;
                      continue;
                  }
                  if(b==1 && h1[locat]==0){
                      h1[locat]=a[i];
                      if(bq==1){
                          bq=1;
                          b=1;
                      }else{
                          bq=2;
                          b=2;
                      }
       
                      continue;
                  }
                  if(b==2 && h2[locat2]!=0){
                      int t=h2[locat2];
                      h2[locat2]=a[i];
                      a[i]=t;
                      i--;
                      b=1;
                      continue;
                  }
                  if(b==2 && h2[locat2]==0){
                      h2[locat2]=a[i];
                      if(bq==2){
                          bq=2;
                          b=2;
                      }else{
                          bq=1;
                          b=1;
                      }
                      continue;
                  }
       
              }
              printf("Case %d:\n",cc+1);
              int cou=0;
              for(i=0;i<n1;i++){
                  if(h1[i]!=0){
                      cou++;
                      break;
                  }
              }
              if(cou!=0){
                  printf("Table 1\n");
                  for(int i=0;i<n1;i++){
                      if(h1[i]!=0){
                          printf("%d:%d\n",i,h1[i]);
                      }
                  }
              }
       
              cou=0;
              for(i=0;i<n2;i++){
                  if(h2[i]!=0){
                      cou++;
                      break;
                  }
              }
              if(cou!=0){
                  printf("Table 2\n");
                  for(int i=0;i<n2;i++){
                      if(h2[i]!=0){
                          printf("%d:%d\n",i,h2[i]);
                      }
                  }
              }
              cc++;
          }
          return 0;
      }


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值