上一篇我们了解了哈希表与哈希冲突的基本概念,并且展示了一种哈希冲突的解决方法,今天我们来了解第二种哈希冲突的解决方法
开散列法,又叫链地址法
开散列法:首先对关键码集合用散列函数计算出散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个无头结点的单链表连接起来,各链表的头结点存储在哈希表中,也就相当于,此时存储各个头结点的这个数组,是一个指针数组,这个数组里面存的是每一个单链表头结点指针
下面就是具体的代码实现
hash.h
#pragma once
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#define HASHMAXSIZE 1000
typedef int keytype;
typedef int valtype;
typedef int(*HashFunc)(keytype key);
typedef struct HashElem{
keytype key;
valtype value;
struct HashElem *next;
struct HashElem *pre;
}HashElem;
typedef struct HashTable{
HashElem* data[HASHMAXSIZE];
size_t size;
HashFunc func;
}HashTable;
void HashInit(HashTable *ht,HashFunc hash_func);
int HashFuncDefault(keytype key);
void HashInsert(HashTable *ht,keytype key,valtype value);
int HashFind(HashTable *ht,keytype key,valtype *value,HashElem **pre);
void HashRemove(HashTable *ht,keytype key);
void Hashdestroy(HashTable *ht);
hash.c
#include <stdio.h>
#include "hash.h"
//哈希桶
void HashInit(HashTable *ht,HashFunc hash_func)
{
if(ht == NULL)
{
return;
}
ht->size = 0;
ht->func = hash_func;
size_t i = 0;
for(;i < HASHMAXSIZE;i++)
{
ht->data[i] = NULL;
}
return;
}
int HashFuncDefault(keytype key)
{
return key % HASHMAXSIZE;
}
HashElem *creat(keytype key,valtype value)
{
HashElem *newnode = (HashElem *)malloc(sizeof(HashElem));
newnode->key = key;
newnode->value = value;
newnode->next = NULL;
return;
}
void HashInsert(HashTable *ht,keytype key,valtype value)
{
if(ht == NULL)
{
return;
}
int offset = HashFuncDefault(key);
HashElem* cur = ht->data[offset];
while(1)
{
while(cur != NULL)
{
if(cur->key = key)
{
return;
}
cur = cur->next;
}
HashElem *newnode = creat(key,value);
newnode ->next = ht->data[offset];
ht->data[offset] = newnode;
ht->size++;
return;
}
++ht->size;
return;
}
int HashFind(HashTable *ht,keytype key,valtype *value,HashElem **pre)
{
if(ht == NULL)
{
return 0;
}
int offset = HashFuncDefault(key);
HashElem* cur = ht->data[offset];
HashElem *prev = NULL;
while(cur != NULL)
{
if(cur->key == key)
{
*value = cur->value;
*pre = prev;
return 1;
}
prev = cur;
cur = cur->next;
}
return 0;
}
void HashRemove(HashTable *ht,keytype key)
{
if(ht == NULL)
{
return;
}
int offset = HashFuncDefault(key);
HashElem* cur = ht->data[offset];
HashElem *pre = NULL;
valtype value;
int ret = HashFind(ht,key,&value,&pre);
if(ret == 1)
{
while(cur != NULL)
{
if(cur->value == ht->data[offset]->value)
{
ht->data[offset] = cur->next;
free(cur);
return;
}
else
{
pre->next = cur->next;
free(cur);
return;
}
}
}
return;
}
void Hashdestroy(HashTable *ht)
{
if(ht == NULL)
{
return;
}
size_t i = 0;
for(;i < HASHMAXSIZE;i++)
{
ht->data[i] = NULL;
}
return;
}
///////
//test
///////
#define HEADER printf("\n==========%s==========\n",__FUNCTION__)
void Hashprint(HashTable *ht)
{
if(ht == NULL)
{
return;
}
size_t i = 0;
for(;i < HASHMAXSIZE;i++)
{
HashElem* cur = ht->data[i];
while(cur != NULL) {
printf("%d [%d|%d] ",i, cur->key, cur->value);
cur = cur->next;
}
}
printf("\n");
}
void testinsert()
{
HEADER;
HashTable hash;
HashInit(&hash,HashFuncDefault);
HashInsert(&hash,1,1);
HashInsert(&hash,2,2);
HashInsert(&hash,2,10);
HashInsert(&hash,11,11);
HashInsert(&hash,12,12);
Hashprint(&hash);
}
void testfind()
{
HEADER;
HashTable hash;
HashInit(&hash,HashFuncDefault);
HashInsert(&hash,1,1);
HashInsert(&hash,2,2);
HashInsert(&hash,2,10);
HashInsert(&hash,11,11);
HashInsert(&hash,12,12);
Hashprint(&hash);
valtype value;
HashElem *pre;
int ret = HashFind(&hash,11,&value,&pre);
printf("expected is 1 ,actul is %d\n",ret);
printf("expected is 11 ,actul is %d\n",value);
}
void testremove()
{
HEADER;
HashTable hash;
HashInit(&hash,HashFuncDefault);
HashInsert(&hash,1,1);
HashInsert(&hash,2,2);
HashInsert(&hash,2,10);
HashInsert(&hash,11,11);
HashInsert(&hash,12,12);
Hashprint(&hash);
HashRemove(&hash,2);
Hashprint(&hash);
//valtype value;
//int ret = HashFind(&hash,11,&value);
//printf("expected is 1 ,actul is %d\n",ret);
}
int main()
{
testinsert();
testfind();
testremove();
return 0;
}
下面就是测试结果