仅给出一个以“除留余数法”+“开放定址法(线性探测再散列)”实现的哈希表代码:
#pragma once
#define SUCCESS 1
#define UNSUCCESS 0
#define DUPLICATE -1
#define NULLKEY -111
#define OK 1
#define ERROR -1
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)< (b))
#define LQ(a,b) ((a)<=(b))
typedef int KeyType;
typedef int info;
typedef struct
{
KeyType key;
//info otherinfo;
}ElemType;
typedef struct
{
ElemType *elem;
int count; //当前hash表元素个数
int sizeindex; //hashsize[sizeindex]为当前hash表当前容量
}HashTable;
int InitHashTable(HashTable &H); // 构造一个空的哈希表
void DestroyHashTable(HashTable &H);
int Hash(KeyType K); // 除留余数法(m为表长,全局变量)
void collision(int &p,int d);// 开放定址法处理冲突:线性探测再散列
int SearchHash(HashTable H,KeyType K,int &p,int &c); //搜索的是关键字
int InsertHash(HashTable &H,ElemType e); //插入的是元素
void RecreateHashTable(HashTable &H) /* 重建哈希表 */;
void TraverseHash(HashTable H);
#include "hash.h"
#include <stdio.h>
#include <stdlib.h>
int hashsize[]={13,19,29,37}; // 哈希表容量递增表,一个合适的素数序列
int m = 0; // 哈希表表长,全局变量
int InitHashTable(HashTable &H) // 构造一个空的哈希表
{
int i;
H.count=0; // 当前元素个数为0
H.sizeindex=0; // 初始存储容量为hashsize[0]
m = hashsize[0];
H.elem=(ElemType*)malloc(m*sizeof(ElemType));
if(!H.elem)
exit(0); // 存储分配失败
for(i=0;i<m;i++)
H.elem[i].key=NULLKEY; // 未填记录的标志
return OK;
} //InitHashTable
void DestroyHashTable(HashTable &H) //哈希表H存在,销毁哈希表H
{
if (H.elem != NULL) free(H.elem);
H.elem=NULL;
H.count=0;
H.sizeindex=0;
} //DestroyHashTable
int Hash(KeyType K) // 除留余数法(m为表长,全局变量)
{
return K%m;
} //Hash
void collision(int &p,int d) // 开放定址法处理冲突:线性探测再散列
{
p=(p+d)%m;
} //collision
//在开放地址hashH中查找关键字K的元素,若查找成功,以p指示待查元素数据在表中位置并返回SUCCESS
//否则以p指示插入位置并返回UNSUCCESS
//c用以计冲突次数,其初值为0,供建表插入时参考
int SearchHash(HashTable H,KeyType K,int &p,int &c)
{
p=Hash(K); //构造哈希函数
while(H.elem[p].key!=NULLKEY&&!EQ(K,H.elem[p].key))
{
collision(p,++c); //冲突检测
if(c>=m) break;
}
if(H.elem[p].key!=NULLKEY&&EQ(K,H.elem[p].key))
return SUCCESS;
else
return UNSUCCESS;
}//SearchHash
int InsertHash(HashTable &H,ElemType e)
{
// 查找不成功时插入数据元素e到开放定址哈希表H中,并返回OK;若冲突次数过大,则重建哈希表
int c,p;
c=0;
if(SearchHash(H,e.key,p,c)) // 表中已有与e有相同关键字的元素
return DUPLICATE;
else if(c<hashsize[H.sizeindex]/2) // 冲突次数c未达到上限,(c的阀值可调)
{
// 插入e
H.elem[p]=e;
++H.count;
return OK;
}
else
RecreateHashTable(H); // 重建哈希表
return ERROR;
}
void RecreateHashTable(HashTable &H) // 重建哈希表
{
int i,count=H.count;
ElemType *p,*elem=(ElemType*)malloc(count*sizeof(ElemType));
p=elem;
printf("重建哈希表\n");
for(i=0;i<m;i++) // 保存原有的数据到临时申请了空间的elem中
if((H.elem+i)->key!=NULLKEY) // 该单元有数据
*p++=*(H.elem+i);
H.count=0;
H.sizeindex++; // 增大存储容量
m=hashsize[H.sizeindex];
p=(ElemType*)realloc(H.elem,m*sizeof(ElemType));
if(!p)
exit(-1); // 存储分配失败
H.elem=p;
for(i=0;i<m;i++)
H.elem[i].key=NULLKEY; // 未填记录的标志(初始化)
for(p=elem;p<elem+count;p++) // 将原有的数据按照新的表长插入到重建的哈希表中
InsertHash(H,*p);
free(elem);elem = NULL;
}//RecreateHashTable
void TraverseHash(HashTable H)
{
int i;
for (i = 0; i < m; i++)
printf("%2d ", i);
putchar('\n');
for (i = 0; i < m; i++)
if (H.elem[i].key != NULLKEY)
printf("%2d ", H.elem[i].key);
else
printf(" ");
putchar('\n');
putchar('\n');
}
测试代码:
int main()
{
HashTable H;
int i;
KeyType arr[] = {19, 14, 23, 01, 68, 20, 84, 27, 55, 11, 10, 79}; //关键字
int n = sizeof(arr)/sizeof(arr[0]);
InitHashTable(H);
ElemType e;
for (i = 0; i < n - 1; i++)//n
{
e.key = arr[i];
InsertHash(H, e); //插入的是元素
printf("插入 %d 后:\n", e.key);
TraverseHash(H);
}
printf("Hash表元素为:\n");
TraverseHash(H);
for (i = 0; i < n; i++)
{
int p = 0, c = 0;
int ret = SearchHash(H, arr[i], p, c); //查找的是关键字
if(ret)
printf("查找 %2d 成功, p = %2d, key = %2d, c = %d\n",arr[i], p, H.elem[p].key, c);
else
printf("查找 %d 失败\n", arr[i]);
}
DestroyHashTable(H);
getchar();
return 1;
}