上一章中,我們實現了hash表
中的插入
、搜尋
和刪除
介面,我們在初始化hash表
時固定了大小為53
,為了方便擴充套件,本章將介紹如何修改hash表
的大小。
現在,我們的hash表
是固定大小(53
)的,當插入越來越多資料時,我們的hash表
就會被插滿,這個問題有兩個原因:
雜湊表的效能隨著高衝突率而降低
我們的'hash表'只能儲存固定數量的記錄,如果我們儲存更多,將無法插入資料
為了減少hash表
被插滿的情況發生,當插入很多資料時,我們可以增大hash表
的大小,hash表
中的count
屬性代表已經插入的資料條數,在每次插入和刪除時,我們計算表的「負載」,或插入的數量和總的大小的比率,如果它高於或低於某些值,我們會減小或擴大hash表
的大小。
我們定義如下規則:
如果負載》0.7
,就擴大
如果負載<0.1
,就縮小
要調整大小,我們建立乙個大約是當前大小的一半或兩倍的新雜湊表,並將所有未刪除的項插入其中。
我們的新hash表
大小應該是大約是當前大小的兩倍或一半的素數,找到新的hash表
大小並非易事。為了確定hash表
的大小,我們現設定乙個最基本的大小,然後將實際大小定義為大於基本大小的第乙個素數。擴大時,我們先將基本大小加倍,找到第乙個更大的素數,然後作為hash表
的大小,縮小時,我們將大小減半並找到下乙個更大的素數。
我們先從基本大小50
開始,我們使用最簡單粗暴的方法通過檢查每個連續數是否為素數來查詢下乙個素數。這個簡單粗暴的方法看起來不是很理想,但是我們實際需要檢查的值很少,並且花費的時間超過了重新雜湊表中每個專案所花費的時間。
// prime.h
int is_prime(const int x);
int next_prime(int x);
// prime.c
#include #include "prime.h"
/* * return whether x is prime or not
* * returns:
* 1 - prime
* 0 - not prime
* -1 - undefined (i.e. x < 2)
*/int is_prime(const int x)
if (x < 4)
if ((x % 2) == 0)
for (int i = 3; i <= floor(sqrt((double) x)); i += 2)
}return 1;}/*
* return the next prime after x, or x if x is prime
*/int next_prime(int x)
return x;
}
下一步,我們需要修改ht_new
函式,使之可以在建立hash表
時指定大小,為此我們要建立乙個新的函式ht_new_sized
,在ht_new
中我們呼叫ht_new_sized
並給我們的hash表
乙個預設大小:
// hash_table.c
static ht_hash_table* ht_new_sized(const int base_size)
ht_hash_table* ht_new()
現在一切準備就緒。在我們的設定hash表
大小函式中,我們需要檢查以確保我們沒有將雜湊表的大小減小到最小值以下,然後,我們初始化乙個所需大小的新hash表
,原表中所有非null
或者未被刪除的都會插入到新hash表
中,然後我們在刪除舊的hash
表之前將屬性賦值給新的hash表
。
// hash_table.c
static void ht_resize(ht_hash_table* ht, const int base_size)
ht_hash_table* new_ht = ht_new_sized(base_size);
for (int i = 0; i < ht->size; i++)
}ht->base_size = new_ht->base_size;
ht->count = new_ht->count;
// to delete new_ht, we give it ht's size and items
const int tmp_size = ht->size;
ht->size = new_ht->size;
new_ht->size = tmp_size;
ht_item** tmp_items = ht->items;
ht->items = new_ht->items;
new_ht->items = tmp_items;
ht_del_hash_table(new_ht);
}
為了簡化設定大小,我們定義了兩個函式:
// hash_table.c
static void ht_resize_up(ht_hash_table* ht)
static void ht_resize_down(ht_hash_table* ht)
要執行調整大小,我們先檢查插入和刪除時hash表
上的負載。 如果它高於或低於0.7和0.1的預定義限制,我們分別調高或調低。
為了避免進行浮點運算,我們將計數乘以100
,並檢查它是高於還是低於70
或10
:
// hash_table.c
void ht_insert(ht_hash_table* ht, const char* key, const char* value)
// ...
}void ht_delete(ht_hash_table* ht, const char* key)
// ...
}
C語言實現乙個簡易的掃雷2
ifndef game h define game h define crt secure no warnings 1 include include include include define rows 11 define cols 11 define count 10 void init bo...
C語言實現乙個簡易的Hash table 二
上一章,簡單介紹了hash table,並提出了本教程中要實現的幾個hash table的方法,有search a,k insert a,k,v 和delete a,k 本章將介紹hash table使用的資料結構。hash表中儲存的每一項key value的資料結構 hash table.h ty...
C語言實現乙個簡易的Hash table 三
上一章,我們講了hash表的資料結構,並簡單實現了hash表的初始化與刪除操作,這一章我們會講解hash函式和實現演算法,並手動實現乙個hash函式。本教程中我們實現的hash函式將會實現如下操作 我們將會設計乙個普通的字串hash函式,在偽 中表示如下 function hash string,a...