问答题 构造散列表,采用开地址法处理冲突,根据下面公式计算下一地址:
   d1=H(key)=3*key/%11
   di=(di-1+(7*key))/%11    (i=2,3,…)
   试在0~10的散列地址空间中对关键字序列(22,41,53,46,30,13,01,67)构造散列表,求等概率情况下查找成功的平均查找长度,并设计生成这个散列表的完整的函数。
【正确答案】(1)分析
   利用公式计算元素存放的地址:
   22:d1=0 41:d1=2 53:d1=5 46:d1=6 30:d1=2,d2=3  13:d1=6,d2=9
   01:d1=3,d2=10    67:d1=3,d2=10,d3=6,d4=2,d5=9,d6=5,d7=1
   得到的散列表:
0 1 2 3 4 5 6 7 8 9 10
22 67 41 30   53 46     13 01

   等概率条件下查找成功的平均查找长度:17/8。
   (2)数据结构
   #define REGION_LEN 11  /*基本区域长度*/
   typedef struct{
     int key;    /*字典元素的关键码字段*/
     int value;    /*字典元素的属性字段*/
   }DicElement;
   typedef struct{
     DicElement element[REGION_LEN];
     int m;    /*n<=REGION LEN,为字典中的元素个数*/
   }HashDictionary;
   (3)思路
   此法选用了一个散列函数H,以关键码为自变量,产生一个0至REGION LEN-1之间的数为地址。如果发生碰撞,则利用给出的递推公式计算下一个地址。递推公式以宏定义的形式给出。
   生成散列表的函数:设计其含有一个int参数limit,用以控制字典中的元素总个数;返回值即为指向生成好的散列表的指针。首先为散列表申请空间并完成初始化。然后判断用户给出的字典元素总个数是否满足要求(不能“溢出”),接着进入while循环,不断要求用户给出关键码值,并利用散列函数将它们存入散列表。这里忽略了对元素属性的操作。返回指针值。
   (4)算法
   #define H1(key)(3*(key))/%(REGION_LEN)
   /*用宏定义给出递归公式*/
   #define H2(H,key)((H)+(7*(key)))/%(REGION_LEN)
   /*这个公式的具体使用参见程序*/
   #define null-1    /*null为空结点标记*/
   HashDictionary*create(int limit){
     int d,i;
     intkey;
     HashDictionary*p;
     p=(HashDictionary*)malloc(sizeof(HashDictionary));  /*申请空间*/
     if(p==NULL){
       printf("Out of space!\n");
       return(p);
     }
     for(i=0;i<REGION_LEN;i++)p->element[i].key=null;  /*初始化*/
     if(limit>REGION_LEN){
     /*如果用户提供的字典元素总数会使表发生"溢出"*/
       printf("Too many keys.Can put/%d keys in Dic only.\n",REGION_LEN);
        limit=REGION_LEN;
       }
       i=0:
       while(i<limit){/*依次要求用户输入key值,并按公式放入表中*/
         printf("\nPlease input the key:");
         scanf("/%d",&key);
         d=H1(key);
         if(p->element[d].key==null)    /*没有发生碰撞*/
           p->element[d].key=key;
         else{
           while(p->element[d].key!=null)d=H2(d,key);
           /*按递归公式寻找可以放入的地址*/
           p->element[d].key=key;
       }
       i++:
     }
     p->m=limit;    /*修改字典元素总数*/
     return(p);
   }
   (5)代价分析
   设共有n(不大于REGION_LEN)个元素需要放入表中。最好情形是它们互不碰撞,代价为O(n);最坏情形是从放入第二个元素开始均有碰撞,这时为二重while循环,循环次数最多为0+1+2+…+(n-1)=O(n2)。
【答案解析】