雜湊表(上) 開放定址法

2021-09-28 20:20:40 字數 3156 閱讀 3689

概述

雜湊表,又稱雜湊表,hash表。雜湊表是一種特殊的資料結構,它同陣列、鍊錶以及二叉排序樹等相比較有很明顯的區別,它能夠快速定位到想要查詢的記錄,而不是與表中存在的記錄的關鍵字進行比較來進行查詢。這個源於雜湊表設計的特殊性,它採用了函式對映的思想將記錄的儲存位置與記錄的關鍵字關聯起來,從而能夠很快速地進行查詢。

設計思想

hash表採用乙個對映函式 f : key —> address 將關鍵字對映到該記錄在表中的儲存位置,從而在想要查詢該記錄時,可以直接根據關鍵字和對映關係計算出該記錄在表中的儲存位置,通常情況下,這種對映關係稱作為hash函式,而通過hash函式和關鍵字計算出來的儲存位置(注意這裡的儲存位置只是表中的儲存位置,並不是實際的實體地址)稱作為hash位址。

雜湊函式

1)直接定址法 

取關鍵字或者關鍵字的某個線性函式為hash位址,即hash(key)=a*key+b

2)除留餘數法 

如果知道hash表的最大長度為m,可以取不大於m的最大質數p,然後對關鍵字進行取餘運算,hash(key)=key%p。 

在這裡p的選取非常關鍵,p選擇的好的話,能夠最大程度地減少衝突,p一般取不大於m的最大質數。

3)平方取中法 

對關鍵字進行平方運算,然後取結果的中間幾位作為hash位址。假如有以下關鍵字序列,平方之後的結果為,那麼可以取作為hash位址。

4)摺疊法 

將關鍵字拆分成幾部分,然後將這幾部分組合在一起,以特定的方式進行轉化形成hash位址。假如知道圖書的isbn號為8903-241-23,可以將hash(key)=89+03+24+12+3作為hash位址。

衝突處理策略

無論利用上述哪種hash函式計算hash位址,難免會產生不同元素的hash位址一樣,那麼這樣就產生了衝突,那麼如何避免衝突是一件很關鍵的事。下面有兩種方式解決衝突:開放定址法與分離鏈結法(鏈位址法)。由於篇幅問題,這篇博文主要介紹開放定址法。

開放定址法

當乙個關鍵字和另乙個關鍵字發生衝突時,使用某種探測技術在hash表中形成乙個探測序列,然後沿著這個探測序列依次查詢下去,當碰到乙個空的單元時,則插入其中。基本公式為:hash(key) = (hash(key)+di)mod tablesize。其中di為增量序列,tablesize為表長。根據di的不同我們又可以分為線性探測,平方(二次)探測,雙雜湊探測。 

1)線性探測 

以增量序列 1,2,……,(tablesize -1)迴圈試探下乙個儲存位址,即di = i。如果table[index+di]為空則進行插入,反之試探下乙個增量。但是線性探測也有弊端,就是會造成元素聚集現象,降低查詢效率。具體例子如下圖: 

特別對於開放定址法的刪除操作,不能簡單的進行物理刪除,因為對於同義詞來說,這個位址可能在其查詢路徑上,若物理刪除的話,會中斷查詢路徑,故只能設定刪除標誌。

//插入函式,利用線性探測法 

bool insert_linear_probing(int num)

int index = this->hash(num);

if(this->data[index] == max)else

index = (index+i)%this->length; 

this->data[index] = num;

}if(this->delete_flag[index] == 1)

this->size++;

return true;

}

3)雙雜湊探測 

di 為i*h2(key),h2(key)是另乙個雜湊函式。探測序列成:h2(key),2h2(key),3h2(key),……。對任意的key,h2(key) ≠ 0 !探測序列還應該保證所有的雜湊儲存單元都應該能夠被探測到。選擇以下形式有良好的效果: 

h2(key) = p - (key mod p) 

其中:p < tablesize,p、tablesize都是素數。

例子全部**:這裡只利用線性探測思想解決衝突。其他2種節約時間未實現。

#include #include #include using namespace std;

const int max = 65535;

class hashtable

}//判斷素數函式 

bool isprime(int num)else if( num == 2)else}}

return flag;

}//尋求小於表長的最大素數

int getmaxprime()}}

//hash函式

int hash(int num)

//插入函式,利用線性探測法 

bool insert_linear_probing(int num)

int index = this->hash(num);

if(this->data[index] == max)else

index = (index+i)%this->length; 

this->data[index] = num;

}if(this->delete_flag[index] == 1)

this->size++;

return true;

}//建表函式

void create_linear_probing(int* num , int size)

}//查詢函式 

int find_linear_probing(int num)elseelse   

}else }}

return flag; 

}//線性探測的刪除函式

bool delete_linear_probing(int num)else

}void print()

cout

}cout<>length;

cout

data = new int[size];

cout

}hashtable hashtable(length);

hashtable.create_linear_probing(data,size);

cout

cout

cout<

截圖1: 

截圖2: 

開放定址法實現雜湊表

使用分離鏈結法實現雜湊表時需要額外的空間來儲存指標,而且需要給新單元動態分配空間,導致演算法的速度減慢。開放定址法一次分配表的大小,可以使用線性雜湊,平方雜湊,雙重雜湊等等方法,這些方法除了雜湊函式不相同之外,對於雜湊表的大小要求也不一樣。平方雜湊需要使表的大小是儲存元素的兩倍以上,這樣總能找到空槽...

雜湊 開放定址法

引起雜湊衝突的乙個原因可能是 雜湊函式設計不夠合理。雜湊函式設計原則 雜湊函式的定義域必須包括需要儲存的全部關鍵碼,而如果雜湊表允許有m個位址時,其值域必須在0到m 1之間 雜湊函式計算出來的位址能均勻分布在整個空間中 雜湊函式應該比較簡單 閉雜湊typedef int keytype typede...

雜湊表查詢 開放定址法

雜湊表 也叫雜湊表 是根據關鍵字值而直接進行訪問的資料結構。通過把關鍵字值對映到表中乙個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表。雜湊函式的構造方法 1 直接定址法 2 除留餘數法 3 平方取中法 4 摺疊法 5 數值分析法 本文採用除留餘數法構造雜湊函式...