首先是需要定义一个散列表的结构以及一些相关的常数。其中HashTable就是散列表结构。结构当中的elem为一个动态数组。
#define SUCCESS 1
#define UNSUCCESS 0
/* 定义散列表长为数组的长度 */
#define HASHSIZE 12
#define NULLKEY -32768
typedef struct{
/* 数据元素存储基址,动态分配数组 */
int *elem;
/* 当前数据元素个数 */
int count;
} HashTable;
/* 散列表表长,全局变量 */
int m = 0;
有了结构的定义,我们可以对散列表进行初始化。
/* 初始化散列表 */
Status InitHashTable(HashTable *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 OK;
}
为了插入时计算地址,我们需要定义散列函数,散列函数可以根据不同情况更改算法。
/* 散列函数 */
int Hash(int key){
/* 除留余数法 */
return key % m;
}
初始化完成后,我们可以对散列表进行插入操作。假设我们插入的关键字集合就是前面的
{12,67,56,16,25,37,22,29,15,47,48,34}。
/* 插入关键字进散列表 */
void InsertHash(HashTable *H, int key){
/* 求散列地址 */
int addr = Hash(key);
/* 如果不为空,则冲突 */
while (H->elem[addr] != NULLKEY)
/* 开放定址法的线性探测 */
addr = (addr + 1) % m;
/* 直到有空位后插入关键字 */
H->elem[addr] = key;
}
代码中插入关键字时,首先算出散列地址,如果当前地址不为空关键字,则说明有冲突。此时我们应用开放定址法的线性探测进行重新寻址,此处也可更改为链地址法等其他解决冲突的办法。
散列表存在后,我们在需要时就可以通过散列表查找要的记录。
/* 散列表查找关键字 */
Status SearchHash(HashTable H, int key, int *addr){
/* 求散列地址 */
*addr = Hash(key);
/* 如果不为空,则冲突 */
while (H.elem[*addr] != key){
/* 开放定址法的线性探测 */
*addr = (*addr + 1) % m;
if (H.elem[*addr] == NULLKEY || *addr == Hash(key)){
/* 如果循环回到原点则说明关键字不存在 */
return UNSUCCESS;
}
}
return SUCCESS;
}
查找的代码与插入的代码非常类似,只需做一个不存在关键字的判断而已。