上一章中,咱们使用了双重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