开地址哈希表本质上是一个数组,数组的优势在于可以使用下标随机访问成员。**data表示存着指针的数组。开地址哈希表数组每个元素是存入的具体节点。链式哈希表数组的每个元素是桶。
链式哈希表中,每个元素放在桶中,桶的深度可扩展所以元素m不限。开地址哈希表把元素存放在表本身,如果顺序插入则随着元素的增多效率越低。每个表有其编号,根据哈希函数决定插入方式,可以更早找到空位,可以提升效率。
链式哈希表的最坏情况是所有元素散列在同一个桶中。开地址哈希表最坏情况是表全满而且要查找的元素不在表中。
//开地址哈希表就是把元素直接存于数组中,根据值确定开始查找空位的位置
typedef struct OHTbl_
{
int positions;//数组长度
int size;//已经放进数的数组元素个数
void **table;//数组
void *vacated;//指向曾经删除过元素的地址
int (*h1)(const void *key);
int (*h2)(const void *key);
int (*match)(const void *key, const void *key2);
void (*destroy)(void *data);
}OHTbl;
1、初始化
int ohtbl_init(OHTBL *htbl, int position, int (*h1)(const void *key), int (*h2)(const void *key), int (*match)(const void *key, const void *key2),void (*destroy)(void *data))
{
int i;
if((htbl->table =(void **)malloc(positions * sizeof(void *))) == NULL)
return -1;
htbl->positions = positions;
for(i = 0; i < htbl->positions; i++)
htbl->table[i] = NULL;
htbl->vacated = &vacated;
htbl->h1 = h1;
htbl->h2 = h2;
htbl->match = match;
htbl->destroy = destroy;
htbl->size = 0;
return 0;
}
2、释放哈希表
void ohtbl_destroy(OHTBL *htbl)
{
int i;
if(htbl->destroy != NULL)
{
for(i = 0; i < htbl->position; i++)
{
//已经删除的地方不再删除
if(htbl->table[i] != NULL && htbl->table[i] != vacated)
htbl->destroy(htbl->table[i]);
}
}
free(htbl->table);
memset(htbl, 0, sizeof(OHTBL));
return;
}
3、插入元素
int ohtbl_insert(OHTBL *htbl, const void *data)
{
void *temp;
int position, i;
//是否已经满了
if(htbl->size == htbl->position)
return -1;
temp = (void *)data;
//数据已经存在
if(ohtbl_lookup(htbl, &temp) == 0)
return 1;
for(i = 0; i < htbl->position; i++)
{
position = (htbl->h1(data) + (i * htbl->h2(data))) % htbl->position;
//该位置无元素
if(htbl->table[position] == null || htbl->table[position] == htbl->vacated)
{
htbl->table[position] = (void *)data;
htbl->size++;
return 0;
}
}
return -1;
}
4、删除元素
int ohtbl_remove(OHTBL *htbl, const void **data)
{
int position, i;
for(i = 0; i < htbl->position; i++)
{
position = (htbl->h1(data) + (i * htbl->h2(data))) % htbl->position;
if(htbl->table[position] == null)
{
return -1;
}
else if(htbl->table[position] == htbl->vacated)
{
continue;
}
else if(htbl->match(htbl->table[position], *data))
{
//只是数组,无链表不需要释放内存
*data = htbl->position;
htbl->table[position] = htbl->vacated;
htbl->size--;
return 0;
}
}
return -1;
}
//判断元素是否存在表中
int ohtbl_lookup(OHTBL *htbl, const void **data)
{
int position, i;
for(i = 0; i < htbl->position; i++)
{
position = (htbl->h1(data) + (i * htbl->h2(data))) % htbl->position;
if(htbl->table[position] == null)
{
return -1;
}
else if(htbl->match(htbl->table[position], *data))
{
*data = t=htbl->position;
return 0;
}
}
return -1;
}