一.散列函数的构造方法
在构造散列函数时,必须注意以下几点:
1)散列函数的定义域必须包含全部关键字,而值域的范围则依赖于散列表的大小。
2)散列函数计算出的地址应尽可能均匀地分布在整个地址空间,尽可能地减少冲突。
3)散列函数应尽量简单,能在较短的时间内计算出任意一个关键字对应的散列地址。下面介绍常用的散列函数。

代码实现:
哈希表的定义
typedef struct per { //结点里的数据体 char name[32]; char tel[16]; }Data_t; typedef struct node //结点 { Data_t data; struct node *pnext; }Node_t; Node_t *hash_table[HASH_SIZE] = {NULL}; //指针数组,存放各个链表的头结点指针基本功能实现:
int hash_function(char key)
{
if (key >= 'a' && key <= 'z')
{
return key-'a';
}
else if (key >= 'A' && key <= 'Z')
{
return key-'A';
}
else
{
return HASH_SIZE-1;
}
}
int insert_hash_table(Node_t **hash_table, Data_t data)
{
int addr = hash_function(data.name[0]);
Node_t *pnode = malloc(sizeof(Node_t));
if (NULL == pnode)
{
printf("malloc error\n");
return -1;
}
pnode->data = data;
pnode->pnext = NULL;
pnode->pnext = hash_table[addr]; //phead
hash_table[addr] = pnode;
return 0;
}
void show_hash_table(Node_t **hash_table)
{
for (int i = 0; i < HASH_SIZE; ++i)
{
Node_t *ptmp = hash_table[i];
while (ptmp != NULL)
{
printf("%s: %s\n", ptmp->data.name, ptmp->data.tel);
ptmp = ptmp->pnext;
}
}
}
Node_t *find_hash_table(Node_t **hash_table, char *name)
{
int addr = hash_function(name[0]);
Node_t *ptmp = hash_table[addr];
while (ptmp != NULL)
{
if (0 == strcmp(ptmp->data.name, name))
{
return ptmp;
}
ptmp = ptmp->pnext;
}
return NULL;
}
void destroy_hash_table(Node_t **hash_table)
{
for (int i = 0; i < HASH_SIZE; ++i)
{
Node_t *ptmp = NULL;
while (hash_table[i] != NULL)
{
ptmp = hash_table[i];
hash_table[i] = ptmp->pnext;
free(ptmp);
}
}
}
二.处理冲突的方法
应该注意到,任何设计出来的散列函数都不可能绝对地避免冲突。为此,必须考虑在发生冲突时应该如何处理,即为产生冲突的关键字寻找下一个“空”的Hash地址。用Hi表示处理冲突中第i次探测得到的散列地址,假设得到的另一个散列地址H1仍然发生冲突,只得继续求下一个地址H2,以此类推,直到Hk不发生冲突为止,则Hk为关键字在表中的地址。
1.开放定址法

注意:采用开放定址法时,不能随便物理删除表中已有元素,否则会截断其他同义词元素的查找路径,删除元素时可以做一个删除标记,进行逻辑删除。但这样做的副作用是:执行多次删除后,表面上看起来散列表很满,实际上有许多位置未利用。
2.拉链法

714



被折叠的 条评论
为什么被折叠?



