[c語言實現]雜湊表
阿新 • • 發佈:2019-02-03
我們在這篇部落格 雜湊表初探
已經初步瞭解了雜湊表的作用,那麼接下來就應該自己實現一下雜湊表了.
同樣的,實現兩種不同的解決雜湊衝突的方案1,閉雜湊 2,雜湊桶
閉雜湊
標頭檔案
#pragma once
#include<stdio.h>
//這個結構體表示雜湊表中的一個元素
//這個元素中同時包含了鍵值對
typedef int KeyType;
typedef char ValType;
typedef enum State
{
Empty, //空狀態
Vaild,//有效狀態
Deleted,//服務於remove
}State;
struct HashTable;
typedef size_t (*HashFunc)(KeyType key,struct HashTable* );
typedef struct HashElem{
KeyType key;
ValType val;
//每個hashtable內元素的狀態``
State state;
}HashElem;
typedef struct HashTable{
HashElem* data;
size_t size;
size_t capacity;
// 填裝因子
float Load_Factor;
//雜湊函式
HashFunc func;
}HashTable;
void HashInit(HashTable* ht,HashFunc hash_func);
void HashDestory(HashTable* ht);
void HashInsert(HashTable* ht,HashElem elem);
ValType HashFind(HashTable* ht, KeyType key);
size_t hash_func( KeyType key,HashTable*ht);
void HashRemove(HashTable* ht, KeyType key);
void HashPrint(HashTable* ht);
各個函式的實現
void HashInit(HashTable* ht,HashFunc hash_func);
初始化雜湊表的工作很簡單,分配儲存雜湊元素的陣列,然後初始化 雜湊表內各個成員的初始值,
值得注意的是我們在申請雜湊表空間之後,陣列內的元素是隨機值,我們要標識該元素是否有效,那麼得把陣列內每個元素的狀態都至為Empty,(簡單的把元素都至為0是不行的,萬一要插入的key是0,那麼會出現此位置已經被佔用的錯誤)
size_t GetHashTableCapacity(HashTable* ht)
{
if(ht == NULL)
return -1;
return ht->capacity;
}
size_t hash_func( KeyType key,HashTable*ht)
{
return key % GetHashTableCapacity(ht);
}
void HashInit(HashTable* ht,HashFunc hash_func)
{
if(ht == NULL || hash_func == NULL)
return;
ht->capacity = 1000;
ht->data= (HashElem*) malloc(sizeof(size_t)* ht->capacity);
ht->size = 0;
ht->func = hash_func;
size_t i = 0;
for( ; i < ht->size; i++ )
{
ht->data[i].state = Empty;
}
}
void HasDestory(HashTable* ht)
銷燬很簡單,不提
void HashInsert(HashTable* ht,HashElem elem)
在雜湊表內插入元素,需要考慮的問題有
1.雜湊表滿了,2插入的key已經存在,3雜湊衝突的問題
void HashInsert(HashTable* ht,HashElem elem)
{
KeyType key = elem.key;
if(ht == NULL)
return;
if(ht->size >= ht->capacity * ht->Load_Factor)
{
//雜湊表已經滿了
return;
}
size_t offset = (*ht->func)(key,ht);
//雜湊衝突
while(ht->data[offset].state == Vaild )
{
offset++;
//在佔用中找到了重複元素
if(ht->data[offset].key == key)
{
//重複元素
printf("重複元素\n");
return;
}
//從頭開始找
if( offset == ht->capacity )
{
//有填充因子存在 不會死迴圈
offset = 0;
}
}
//找到第一個狀態不是 已經佔用的位置插入
ht->data[offset] = elem;`
ht->data[offset].state = Vaild;
ht->size++;
}
ValType HashFind(HashTable* ht, KeyType key)
void HashRemove(HashTable* ht, KeyType key)
查詢要注意的點是:雜湊衝突,往後如果找到empty還沒找到key,就表明key不在雜湊表中,
因為這一點,當我們刪除時不能將key的狀態置為empty,這樣會使再次查詢key以後的元素失敗,所以我們應該為刪除元素獨立設立一個狀態Deleted
ValType HashFind(HashTable* ht, KeyType key)
{
if(ht == NULL)
return -1;
size_t offset = (*hash_func)(key,ht);
//不為空但是又不是 key offset ++
while(1)
{
//碰到查詢的元素是delete狀態
//其實可以忽略,往後找空的就行
if(ht->data[offset].state == Empty)
{
printf("not found \n");
return -1;
}
//排除delete狀態
if(ht->data[offset].key == key && ht->data[offset].state == Vaild )
{
return ht->data[offset].val;
}
offset++;
if(offset == ht->capacity)
offset = 0;
}
//遇到刪除的狀態還得往後找(刪除後面元素的狀態可能是vaild)
//只有遇到空狀態才表示查詢失敗(空表示此位置肯定沒有進行插入,它後面的元素就不可能是雜湊衝突造成的vaild狀態)
}
void HashRemove(HashTable* ht, KeyType key)
{
if(ht == NULL)
return ;
size_t offset = (*hash_func)(key, ht);
while(ht->data[offset].state != Empty)
{
if(ht->data[offset].key == key && ht->data[offset].state == Vaild)
{
ht->data[offset].state = Deleted;
return;
}
offset++;
if(offset == ht->capacity)
{
offset = 0;
}
}
printf("not found \n");
return;
}
void HashPrint(HashTable* ht)
{
if(ht == NULL)
return;
size_t i = 0;
for( ; i < ht->capacity; i++ )
{
if(ht->data[i].state != Vaild)
{
continue;
}
printf("[%lu|%d|%d] " ,i, ht->data[i].key, ht->data[i].val);
}
printf("\n");
}
雜湊桶
#pragma once
#include<stdio.h>
#define HashMaxSize 1000
typedef int KeyType;
typedef char ValType;
typedef size_t (*HashFunc)(KeyType key );
typedef struct HashEelem{
KeyType key;
ValType val;
struct HashEelem* next;
}HashEelem;
typedef struct HashTable{
HashEelem* data[HashMaxSize];
size_t size;
//雜湊桶不需要填裝因子和狀態列舉
HashFunc func;
}HashTable;
size_t hash_func( KeyType key);
void HashInit(HashTable* ht,HashFunc hash_func);
void HashDestory(HashTable* ht);
void HashInsert(HashTable* ht,HashEelem elem);
ValType HashFind(HashTable* ht, KeyType key);
size_t hash_func( KeyType key);
void HashRemove(HashTable* ht, KeyType key);
void HashPrint(HashTable* ht);
#include"hash.h"
#include<stdlib.h>
#include<unistd.h>
size_t hash_func( KeyType key)
{
return key % HashMaxSize;
}
void HashInit(HashTable* ht,HashFunc hash_func)
{
if(ht == NULL)
return;
int i = 0;
for( ; i < HashMaxSize; i++ )
{
ht->data[i] = NULL;
}
ht->size = 0;
ht->func = hash_func;
}
void HashDestory(HashTable* ht)
{
if(ht == NULL)
return;
size_t i = 0;
for(; i < HashMaxSize; i++)
{
HashEelem* cur = ht->data[i];
HashEelem* to_delete = NULL;
while(cur)
{
to_delete = cur;
cur= cur->next;
free(to_delete);
to_delete = NULL;
}
}
ht->size = 0;
}
HashEelem* CreateNode(KeyType key, ValType val)
{
HashEelem* elem = (HashEelem*)malloc(sizeof(HashEelem));
if(elem == NULL)
return NULL;
elem->key = key;
elem->val = val;
elem->next = NULL;
return elem;
}
void HashInsert(HashTable* ht,HashEelem elem)
{
if(ht == NULL)
return;
size_t offset = ht->func(elem.key);
if(ht->data[offset] == NULL)
{
ht->data[offset] = CreateNode(elem.key,elem.val);
}
else
{
HashEelem* new_node= CreateNode(elem.key,elem.val);
new_node->next = ht->data[offset];
ht->data[offset] = new_node;
}
ht->size++;
}
ValType HashFind(HashTable* ht, KeyType key)
{
if(ht == NULL)
return -1;
size_t offset = ht->func(key);
HashEelem* cur = ht->data[offset];
while(cur)
{
if(cur->key == key)
{
return cur->val;
}
cur = cur->next;
}
printf("not found\n");
return -1;
}
void HashRemove(HashTable* ht, KeyType key)
{
if(ht == NULL)
return;
size_t offset = ht->func(key);
HashEelem* cur = ht->data[offset];
HashEelem* pre_cur = NULL;
while(cur)
{
if( cur->key == key )
{
break;
}
pre_cur = cur;
cur = cur->next;
}
if(cur == NULL)
{
printf("empty key \n");
}
else if(pre_cur == NULL)
{
free(cur);
cur = NULL;
}
else
{
free(cur);
cur = NULL;
pre_cur->next = NULL;
}
}
void HashPrint(HashTable* ht)
{
size_t i = 0;
for(; i < HashMaxSize; i++)
{
if( ht->data[i] == NULL )
continue;
HashEelem* cur = ht->data[i] ;
printf("第%lu條連結串列結構如下\n",i);
while(cur)
{
/*sleep(1);*/
printf("[key: %d| val: %d] ", cur->key,cur->val);
cur = cur->next;
}
printf("\n");
}
printf("\n");
}