1.构造Hash函数的方法为除留余数法
2..解决冲突办法为平方探查法
当发生冲突时,寻找下一个哈希地址的公式为:
Hi=(H(key)+di)% m
其中:m为哈希表长度,m要求是某个4k+3的质数(di=12,-12,22,-22,…,q2,-q2且q≤m/2)
获取di数组代码:
void Get_d(int d[])
{
int i,sign,k = 1;
d[0] = 0;
for (i = 1; i <= maxSize; ++i)
{
if (i % 2 != 0)
{
sign = 1;
d[i] = k * k;
}
else
{
sign = -1;
d[i] = sign * k*k;
k++;
}
}
}
求m的方法(要求是4k+3的质数):
int IsPrime(int n)
{
int i;
if (n <= 1)
return 0;
for (i = 2; i <= sqrt(n); ++i)
if (n%i == 0)
return 0;
return 1;
}
int NextPrime(int n)
{
int i = n - 1;
if (n <= 2)
{
printf("Error");
}
else
{
while (IsPrime(i) == 0 || (i-3)%4 != 0)
--i;
/*区别或和并的使用,或表示两个条件有一个为真就需要进行循环,
此处只要不是素数或者不是4k+3的序列中的数就要继续循环。
并表示两者都为真的时候才进行循环,此处如果i是素数的话,
第一个条件就为假,则会退出循环,这就不满足需要i还是4k+3序列中的数的要求。*/
}
return i;
}
3.初始化,插入,查找,删除和再散列完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define maxSize 1000
int d[maxSize];
enum KindOfEntry {Legitimate,Empty,Deleted};
typedef struct
{
int Element;
enum KindOfEntry Info;
}Cell;//定义散列表项单元
typedef struct
{
int TableSize;
Cell* TheCells;
}HashTable;//定义散列表
void Get_d(int d[])
{
int i, sign, k = 1;
d[0] = 0;
for (i = 1; i <= maxSize; ++i)
{
if (i % 2 != 0)
{
sign = 1;
d[i] = k * k;
}
else
{
sign = -1;
d[i] = sign * k*k;
k++;
}
}
}
int IsPrime(int n)
{
int i;
if (n <= 1)
return 0;
for (i = 2; i <= sqrt(n); ++i)
if (n%i == 0)
return 0;
return 1;
}
int NextPrime(int n)
{
int i = n - 1;
if (n <= 2)
{
printf("Error");
}
else
{
while (IsPrime(i) == 0 || (i - 3) % 4 != 0)
--i;
}
return i;
}
int Hash(int key, int p)
{
return key % p;
}
HashTable* InitializeTable(int TableSize)
{
HashTable* H;
int i;
H = (HashTable*)malloc(sizeof(HashTable));
H->TableSize = NextPrime(TableSize);
/*给单元数组分配空间*/
H->TheCells = (Cell*)malloc(H->TableSize * sizeof(Cell));
for (i = 0; i < H->TableSize; ++i)
H->TheCells[i].Info = Empty;
return H;
}
int Find(int Key, HashTable* H)
{
int CurrentPos;//当前位置
int CollisionNum;//冲突次数
int HKey;
CollisionNum = 0;
HKey = CurrentPos = Hash(Key, H->TableSize);
while (H->TheCells[CurrentPos].Info != Empty && H->TheCells[CurrentPos].Element != Key)
{
CollisionNum++;
CurrentPos = ( HKey+ d[CollisionNum]) % H->TableSize;//注意d[CollisionNum]不要写成d[CurrentPos],‘%’不要写成'/',这是最初犯过的错
}
return CurrentPos;
}
void Insert(int Key, HashTable* H)
{
int Pos;
Pos = Find(Key, H);
if (H->TheCells[Pos].Info != Legitimate)
{
H->TheCells[Pos].Element = Key;
H->TheCells[Pos].Info = Legitimate;
}
}
void Delete(int Key, HashTable* H)
{
int Pos;
Pos = Find(Key, H);
if (H->TheCells[Pos].Info == Legitimate)
H->TheCells[Pos].Info = Deleted;
}
/*再散列*/
HashTable* ReHash(HashTable* H)
{
int i, OldSize;
Cell* OldCells;
OldSize = H->TableSize;
OldCells = H->TheCells;
H = InitializeTable(2 * OldSize);
/*扫描旧表,元素重新插入到新表*/
for (i = 0; i < OldSize; ++i)
if (OldCells[i].Info == Legitimate)
Insert(OldCells[i].Element, H);
free(OldCells);
return H;
}
int main()
{
HashTable* H;
int r[maxSize] = { 47, 7, 29, 11, 16, 92, 22, 8, 3 };
int i, n = 9;
int m = 2 * n;//表长,假设装填因子为1/2。这里引用天勤P297的例子
Get_d(d);
H = InitializeTable(m);
for (i = 0; i < 9; ++i)
Insert(r[i], H);
/*验证是否插入成功*/
int p,q;
p = Find(7, H);
q = Find(3,H);
printf("p:%d", p);;
printf("\nq:%d\n", q);
/*验证是否删除*/
Delete(7, H);
p = Find(7, H);
if (H->TheCells[p].Info == Deleted)
printf("%d Has been deleted",p);
/*验证再散列*/
H = ReHash(H);
q = Find(3, H);
printf("\nq:%d\n", q);
return 0;
}