在雜湊表基礎知識(1)中,我們介紹了分離鏈結法來解決雜湊衝突。它的乙個缺陷就是需要經常的分配動態記憶體,這是比較花費時間的。本文再介紹解決雜湊表的另外一種方法開放定址法。不需要動態多次的動態分配記憶體。
開放定址法是運用乙個陣列,所有的資料都需要放入這個陣列中,如果發生雜湊衝突,我們通過乙個函式
f 來解決,具體的為如果當前要插入的資料為
x,但是通過雜湊函式ha
sh所確定的插入位置上已經有元素了,那麼我們就運用函式hi
(x)=
(has
h(x)
+f(i
))mo
dtab
lesi
ze,f
(0)=
0 確定備選位置,直到找到乙個空位置。
那麼接下來的問題就是雜湊衝突解決函式f(
i)的確定。我們介紹三種方法,分別是線性探測法(線性函式),平方探測法(平方函式),雙雜湊(雜湊函式)。一.
線性探測
法 f(
i)=i
,這是比較常見的線性函式,當然可以定義其他。它的解決雜湊衝突的本質就是,如果在當前位置發生衝突,那麼我們就選擇相鄰的下乙個位置,直到找到乙個空位置。 (性質
分析)線性探測的預期次數對於插入和不成功查詢來說大約是12
(1+1
/(1−
λ)2)
,成功查詢所需的平均探測次數12
(1+1
/(1−
λ))
,其中λ
表示填充因子,就是雜湊表中的元素與雜湊表的大小的商。這裡我們需要解釋一下開放定址法的查詢策略,它是按照插入策略進行的,首先用ha
sh函式確定乙個位置,然後再用
f 函式來查詢這個元素所在的位置,如果遇到這個元素,那麼就返回元素的位置,這樣就是成功查詢,反之就是查到了乙個空位置,這樣也就是不成功查詢。顯然成功查詢所需的探測次數小於不成功查詢的探測次數,不成功查詢的探測次數和插入時所需的探測次數相同。同時,如果
λ越小,所需的探測次數(無論是插入或者是查詢)越少。 (缺點
分析)1.線性函式容易產生一次聚集的問題,就是資料連續的聚集在雜湊表中的一些區域中,這樣,每當有和這些區域中的元素發生雜湊衝突時,我們都需要多次試菜單元來解決問題。
2.需要填充因子比較的小,原因是填充因子比較大時,所需的探測次數會很多,所以要求雜湊表比較大,而且空餘的位置比較多,有空間浪費的缺點。二.
二次探測
法 針對線性探測法所出現的一次聚集問題,我們可以用二次函式作為解決雜湊衝突函式f=
i2.直觀上是容易理解為什麼它可以解決一次聚集問題,因為如果在ha
sh(x
)mod
tabl
esiz
e 這個位置產生雜湊衝突,下乙個探測的位置為ha
sh(x
)+1m
odta
bles
ize ,再下乙個位置為ha
sh(x
)+4m
odta
bles
ize ,這裡已經發生了查詢位置的跳躍。 (缺點
分析)但是二次探測的突出缺點就是對雜湊表的填裝因子的要求更高,如果填裝因子大於0.5,有可能就不能再繼續填裝資料。
我們需要記住的是如果表的大小是素數,並且表至少有一半為空時,總能插入資料。選擇表的大小盡量選擇素數,同時控制表的填裝因子,不能超過一半。
同時和線性探測類似的是,在二次探測中,如果在同一位置發生衝突,那麼就必須探測相同的備菜單元。這叫做二次聚集,但是比一次聚集危害性要低。三.
雙雜湊
這種方法是選擇另乙個雜湊函式作為解決衝突函式
f ,具體的實現是f(
i)=i
∗has
h2(x
),這可以解決二次聚集問題,但是需要謹慎的選擇ha
sh2 ,原因是如果如果選擇不當,可能發生災難性的錯誤。
接下來我們就來實現開放定址法-二次探測法的c語言的實現。
首先是標頭檔案的定義
#ifndef hash2_h_
#define hash2_h_
struct hashtbl;
typedef struct hashtbl *hash;
struct hashnode;
typedef struct hashnode *entry;
hash init(int tblsize);
int hash_fun(char * s,int tab_size);
int find(char *x,hash h);
void insert(char *x,hash h);
void del(char *x,hash h);
#endif // hash2_h_
主要的結構體定義和相應操作的定義
#include
#include
#include "main.h"
#include
#define n 100
enum kindofentry ;
struct hashnode
;struct hashtbl
;//init
hash init(int tblsize)
return h;
}//hash_fun
int hash_fun(char * s,int tab_size)
return hash_value % tab_size;
}//insert
//find 返回元素所在的位置,為整數型別
int find(char *x,hash h)
if(h->entry[pos]->info==empty)
printf("not found the element\n");
if(h->entry[pos]->info==delete)
printf("the element is delete\n");
if(h->entry[pos]->info==legitimate)
printf("the element is found\n");
return pos;
}//insert
void insert(char *x,hash h)
}//delete
void del(char *x,hash h)
主函式
int main()
字元雜湊基礎知識
定義 字串雜湊,最著名的就是bkdrhash,也就是將字串變成數值,並且最後變成的數值是乙個p進製的數,一般來說p最好為素數.p常見的是131和13331,這是兩個經驗值,出錯率極低。str i 字元陣列 h i 存str 1.i 的雜湊值 p i 存base的i次冪的值 如果h i 和p i 取u...
雜湊表有關的基礎知識(1)
補充知識 namespace的格式基本格式是 namespace exp 有點類似於類,但完全是兩種不同的型別。為了在namespace外使用namespace內的變數我們使用 操作符,如下 exp a exp b 使用namespace可以有效的避免重定義的問題 include using nam...
Hash 雜湊 雜湊 基礎知識梳理
字典的兩種描述方法 跳表和雜湊 hash 限制適用範圍 有序陣列 採用雜湊技術將記錄儲存在一塊連續的儲存空間中,這塊連續的儲存空間愛你被稱為雜湊表或者雜湊表。雜湊技術是在記錄的儲存位置和他的關鍵字之間建立乙個確定的對應關係f 雜湊函式 使得每個關鍵字key對應乙個儲存位置f key 根據這個對應關係...