上一章中,我們使用了雙重Hash
的技術來處理碰撞
,並用了C語言
實現,本章我們將實現Hash表
中的插入
、搜索
和刪除
接口。
實現接口
我們的hash函數
將會實現如下的接口:
// hash_table.h
void ht_insert(ht_hash_table* ht, const char* key, const char* value);
char* ht_search(ht_hash_table* ht, const char* key);
void ht_delete(ht_hash_table* ht, const char* key);
Insert函數
在hash表
中插入一條記錄時,我們需要遍歷整個hash表
知道找到一個空的位置,然後執行插入並將hash表
的大小加1
。hash表
中的count
屬性代表hash表
的大小,在下一章縮放hash表大小
中很有用:
void ht_insert(ht_hash_table* ht, const char* key, const char* value) {
ht_item* item = ht_new_item(key, value);
int index = ht_get_hash(item->key, ht->size, 0);
ht_item* cur_item = ht->items[index];
int i = 1;
while(cur_item != NULL) {
index = ht_get_hash(item->key, ht->size, i);
cur_item = ht->items[index];
++i;
}
ht->items[index] = item;
ht->count++;
}
Search函數
search
和insert
有點相似,但是在while
循環中,我們會檢查記錄的key
是否與我們正在搜索的key
匹配。如果匹配,就會返回這條記錄的value
,沒有匹配到就會返回NULL
:
char* ht_search(ht_hash_table* ht, const char* key) {
int index = ht_get_hash(key, ht->size, 0);
ht_item* item = ht->items[index];
int i = 1;
while (item != NULL) {
if (strcmp(item->key, key) == 0) {
return item->value;
}
index = ht_get_hash(key, ht->size, i);
item = ht->items[index];
i++;
}
return NULL;
}
delete函數
從開放的地址hash表
中刪除比插入或搜索更復雜,因爲存在碰撞
,我們希望刪除的記錄可能是碰撞鏈的一部分。從表中刪除它會破壞該鏈,並且無法在鏈的尾部找到記錄。要解決此問題,我們只需將其標記爲已刪除,而不是真的刪除該記錄。
我們將記錄替換爲指向全局哨兵的指針,再將其標記爲已刪除,該全局哨兵表示包含已刪除的記錄的bucket
:
// hash_table.c
static ht_item HT_DELETED_ITEM = {NULL, NULL};
void ht_delete(ht_hash_table* ht, const char* key) {
int index = ht_get_hash(key, ht->size, 0);
ht_item* item = ht->items[index];
int i = 1;
while (item != NULL) {
if (item != &HT_DELETED_ITEM) {
if (strcmp(item->key, key) == 0) {
ht_del_item(item);
ht->items[index] = &HT_DELETED_ITEM;
}
}
index = ht_get_hash(key, ht->size, i);
item = ht->items[index];
i++;
}
ht->count--;
}
刪除後,我們需要將hash表
的count
屬性減1
。
我們也需要修改下ht_insert
和ht_search
函數,當搜索時,我們需要忽略並跳過已刪除的項,在已刪除項的位置我們可以插入新的記錄:
// hash_table.c
void ht_insert(ht_hash_table* ht, const char* key, const char* value) {
// ...
while (cur_item != NULL && cur_item != &HT_DELETED_ITEM) {
// ...
}
// ...
}
char* ht_search(ht_hash_table* ht, const char* key) {
// ...
while (item != NULL) {
if (item != &HT_DELETED_ITEM) {
if (strcmp(item->key, key) == 0) {
return item->value;
}
}
// ...
}
// ...
}
修改一下
我們的hash表
現在還不支持更新key
的值,如果我們插入兩條相同key
的記錄,key
將會衝突,第二條記錄就會插入到下一個可用的位置,當使用key
搜索時,我們會找到第一條記錄,第二條記錄就永遠不會被找到,現在我們修改下ht_insert
函數,在插入多條相同key
的記錄時,會刪除之前的記錄再插入新的記錄:
// hash_table.c
void ht_insert(ht_hash_table* ht, const char* key, const char* value) {
// ...
while (cur_item != NULL) {
if (cur_item != &HT_DELETED_ITEM) {
if (strcmp(cur_item->key, key) == 0) {
ht_del_item(cur_item);
ht->items[index] = item;
return;
}
}
// ...
}
// ...
}
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。