此方法为最常用的构造散列函数方法。对于散列裴长为m 的散列函数公式为:
f ( key) = key mod p (p 运m)
mod 是取模(求余数)的意思。事实上,这方法不仅可以对关键宇直接取模,也可在折叠、平方取中后再取模。
很显然,本方法的关键就在于选择合适的P , P 如果选得不好,就可能会容易产生同义词。
例如表8-10-4, 我们对于有12 个记录的关键字构造散列表时, 就用了f ( key)=key.mod 12 的方法。比如29 mod 12 = 5 ,所以艺存储在下标为5 的位置。不过这也是存在冲突的可能的,因为12=2 X 6=3 x 4 。如果关键字中有像
18 ( 3x6 ) 、30 (5X 6 ) 、42 ( 7 X 6) 等数字, 官们的余数都为6 ,这就和78 所对应的下标位置冲突了。
2.因此根据前辈们的经验,若散列表表长为m , 通常p 为小子或等于表长(最好接近m ) 的最小质数或不包含小子20 质因子的合数。
3.开放定址法
所谓的开放定址法就是一旦发生了冲突, 就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。它的公式是:
f, ( key ) = ( f ( key ) +dl ) MOD m (d,=1.2 ,乱.. . .... .m-1 )
比如说,我仍的关键字集合为{1 2,67,56, 16,25,37,22,29, 15,47.4B, 34} .表长为12 。
我们用散列函数f ( key) =key mod 12
4.程序示例分析
/*hash.h*/
#ifndef _HASH_H_
#define _HASH_H_
#define NULLKEY -32768
#define HASHSIZE 12
struct hashtable
{
int *elem;
int count;
};
typedef struct hashtable *linkhash;
int inithash(linkhash);
void inserthash(linkhash,int);
int searchhash(linkhash,int);
int hash(int);
#endif
/*main.c*/
#include <stdio.h>
#include <stdlib.h>
#include "hash.h"
int m=0;
int main(void)
{
int temp;
linkhash pt=(linkhash)malloc(15*sizeof(int));
inithash(pt);
printf("please input a key value:");
scanf("%d",&temp);
while(temp!=0)
{
inserthash(pt,temp);
scanf("%d",&temp);
getchar();
}
searchhash(pt,34);
return 0;
}
/*inithash.c*/
#include <stdio.h>
#include <stdlib.h>
#include "hash.h"
extern int m;
int inithash(linkhash h)
{
int i;
m=HASHSIZE;
h->count=m;
h->elem=(int *)malloc(m*sizeof(int));
for(i=0;i<m;i++)
h->elem[i]=NULLKEY;
return 1;
}
/*inserthash.c*/
#include <stdio.h>
#include "hash.h"
extern int m;
void inserthash(linkhash h,int key)
{
int addr;
addr=hash(key);
while(h->elem[addr]!=NULLKEY)
addr=(addr+1)%m;
h->elem[addr]=key;
}
/*searchhash.c*/
#include <stdio.h>
#include "hash.h"
extern int m;
int searchhash(linkhash h,int key)
{
int addr=0;
addr=hash(key);
while(h->elem[addr]!=key)
{
addr=(addr+1)%m;
if(h->elem[addr]==NULLKEY||addr==hash(key))
{
printf("this key value is not exist!\n");
return -1;
}
}
printf("search the value is %d:\n",h->elem[addr]);
return 1;
}