上一章中,咱們使用了雙重Hash
的技術來處理碰撞
,並用了C語言
實現,本章咱們將實現Hash表
中的插入
、搜索
和刪除
接口。函數
咱們的hash函數
將會實現以下的接口:.net
// 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);
在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
和insert
有點類似,可是在while
循環中,咱們會檢查記錄的key
是否與咱們正在搜索的key
匹配。若是匹配,就會返回這條記錄的value
,沒有匹配到就會返回NULL
:code
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; }
從開放的地址hash表
中刪除比插入或搜索更復雜,由於存在碰撞
,咱們但願刪除的記錄多是碰撞鏈的一部分。從表中刪除它會破壞該鏈,而且沒法在鏈的尾部找到記錄。要解決此問題,咱們只需將其標記爲已刪除,而不是真的刪除該記錄。blog
咱們將記錄替換爲指向全局哨兵的指針,再將其標記爲已刪除,該全局哨兵表示包含已刪除的記錄的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
。get
咱們也須要修改下ht_insert
和ht_search
函數,當搜索時,咱們須要忽略並跳過已刪除的項,在已刪除項的位置咱們能夠插入新的記錄:hash
// 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
的記錄時,會刪除以前的記錄再插入新的記錄:it
// 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; } } // ... } // ... }
上一章:處理碰撞 下一章:縮放Hash表大小table