資料結構(十一) 雜湊和字典小結

2021-10-07 16:53:02 字數 4006 閱讀 8820

雜湊衝突與溢位

雜湊效能分析

雜湊實現

看完雜湊和跳表的部分,最大的感受的就是已經開始擺脫基本的資料結構,比如棧和佇列,**的實現開始複雜起來。

雜湊和跳表為了提高降低操作的時間複雜度,都引入了「不可完全**」的概念。跳表多級指標的分布是隨機的,雜湊的hash函式對映是不可完全**的。當我們的資料量達到大量資料級別時,我們的資料結構具有了相對的隨機性。這也是跳表和雜湊與之前資料結構的不同之處。

這一部分引出了乙個新的概念 —— 字典。

字典:字典由一些形如(k,v)的數對所組成的集合,其中k是關鍵字(key),v是與關鍵字k對應的值(value)。比如學號和你的一門成績對應,key便是你的學號,value便是你的成績。

字典是如何和雜湊與跳表聯絡起來的呢?

我認為首先出現的應該是字典的需求,就像上面學號和成績對應的情況。需求出現之後,可以用pair結構體來儲存字典的key和值。

如果將pair型別儲存在陣列中,且key的值是有序的。那麼查詢(二分查詢)的時間複雜度為o(logn),插入和刪除的時間複雜度為o(n)。

因為陣列的隨機訪問在處理pair型別時失效了,我們可以取出任意位置的pair單元,但不知道其中的key和value的具體值。假如我有乙個取出key=「10086」的需求,那麼就只能使用二分查詢,乙個乙個取出pair中的key值,進行比對,時間複雜度為o(logn)。

在動輒百萬行的資料庫中,或者有頻繁訪問的資料表中,這樣的效能是不可接受的。

於是我們引出雜湊和跳表兩個解決方案,其中跳表可以將查詢、插入、刪除的平均時間複雜度降低至θ(logn)。雜湊可以將查詢、插入、刪除的平均時間複雜度降至θ(1)

注意:這裡是平均情況下的漸進等於記法θ,在最壞情況下,跳表和雜湊的查詢、插入、刪除時間複雜度仍為θ(n)

本文著重分析雜湊,跳表部分有餘力時再進行詳細分析。

雜湊:雜湊是字典的一種表示方法,同樣跳表是另一種表示方法。它用乙個雜湊函式(hash function)把字典的數對對映到乙個雜湊表(hash table)的特定位置。如果數對p的關鍵字為k,雜湊函式為f,那麼在理想情況下,p在雜湊表的位置為f(k)。

雜湊的體系結構:

1. 雜湊的實現

2. 雜湊函式

3. 衝突與溢位

4. 雜湊效能分析

雜湊的實現:雜湊表可以由陣列或者陣列+鍊錶實現。**的實現涉及雜湊函式和如何處理衝突和溢位的問題,我將在這些問題分析完成之後在最後列出**。

雜湊函式

雜湊函式是雜湊的核心,理想情況下,可以將關鍵字對映到關鍵字在表中的位址。雜湊函式並不是固定的,使用時要對問題的具體情況設定適合的雜湊函式。我在這裡主要分析直接定址除法取餘雜湊函式。

直接定址函式:f(key) = a*key + b;

優點是計算簡單,且不會產生衝突。

缺點是它只適合關鍵字的分布基本連續的情況,若關鍵字不連續,會導致空位,造成儲存空間的浪費。

例子:還是學號與成績,如果學號區間為「90052——91052」,那麼可設雜湊函式為f(key) = key - 90052,把key對映到雜湊表「0—1000」的位置。之後便可通過對映函式進行基本操作,且時間複雜度為o(1)。

除法雜湊函式:f(key) = key % p;

p為常數,除法雜湊函式是最常用的方法,關鍵是根據問題的情況來選取p,使得關鍵字對映到雜湊表中時可以均勻分布,盡可能減少衝突的發生。

在現階段主要考慮的因素為雜湊表的表長d。

選取p的流程大概如下:

p這樣選取的原因

概括來說就是,p的選取不依賴於key的分布,key可能是等差、等比、隨機和正態等等。我們選取的p要在綜合概率下發生衝突的機率最小。

如果key是間隔為1的等差數列,那麼p任選乙個數都可以做到均勻分布。

如果key是間隔為2的等差數列,那麼當p的因子中有2時,就會產生很多衝突,如果p的因子中沒有2,就會均勻分布。

當我們的表長為d時,取最大接近表長的素數可以保證小於表長的間隔會均勻分布,取大於表長的素數也可以,但因為表中的桶數是固定的,效果合接近表長的素數相同,所以沒必要取大於表長的素數。

衝突:當兩個或兩個以上關鍵字對映到同乙個桶時,便發生了衝突。

溢位:如果雜湊表沒有空間儲存乙個新數對,則發生溢位,只有在陣列實現的鍊錶中有這種情況。

處理衝突的方法

陣列實現:

線性探測法:

假設衝突發生在第i個桶,便探測第i+1個桶,若該桶為空,則將插入的新單元放入第i+1個桶。若不為空,則繼續探測,直到找到空的桶插入,或返回到第i個桶(把雜湊表當作邏輯環,表示表已滿)。

線性探測法並不適合經常性的插入和刪除操作,特別是刪除操作,刪除乙個數對,要移動若干個數對。即使是邏輯刪除,也要不定時進行更新雜湊表。

再雜湊法

需要使用兩個雜湊函式,當通過第乙個雜湊函式得到的位址發生衝突時,則利用第二個雜湊函式計算該關鍵字的位址增量。再雜湊法最多經過m-1次探測就會遍歷表中的所有位置。

公式:fi = (f(key) + i*fi-1(key)+a)% m;

鍊錶實現:

鏈結法

為了避免線性探測法的「堆積」問題和溢位,我們可以把所有對映到同一桶的數對儲存到乙個線性鍊錶中。如果表長為m,那麼便有m個鍊錶,查詢、插入、刪除操作在對映到某乙個桶之後便在鍊錶上進行。

鏈結法適用於經常需要插入刪除的情況,因為基本操作在鍊錶的實現比較簡潔。

這裡實現的是使用線性探查法的雜湊實現,沒有實現刪除方法

template

<

classe,

class

k>

class

hashtable

;template

<

classk,

class

e>

hashtable

::hashtable

(int thedivisor)

}template

<

classk,

class

e>

hashtable::~

hashtable()

}template

<

classk,

class

e>

int hashtable

::hsearch

(const k& thekey)

const

j =(j+1

)% divisor;

}while

(j != i)

;return j;

}template

<

classk,

class

e>

pair<

const k, e>

* hashtable

::find

(const k& thekey)

const

template

<

classk,

class

e>

void hashtable

::insert

(const pair<

const k, e>

& thepair)

else

else

}}

刪除方法敘述

第一種:對刪除的元素進行標記,進行邏輯刪除。並定期維護雜湊表,把標記刪除的元素物理刪除。

資料結構(十一)雜湊表結構

雜湊表實踐 h x x mod 10 的結果 4371 mod 10 1 1323 mod 10 3 6173 mod 10 3 4199 mod 10 9 4344 mod 10 4 9679 mod 10 9 1989 mod 10 9 將雜湊到同乙個值的所有元素保留在乙個鍊錶中 hi x ha...

資料結構 雜湊

裝填因子 key的個數與表長的比值。雜湊表查詢成功的平均查詢長度,查詢失敗的平均查詢長度都是期望,期望怎麼求,平均查詢長度就怎麼求。雜湊表這裡有兩種實現方式 線性開型定址雜湊,鍊錶雜湊。1.線性開型定址雜湊 陣列實現,資料個數不大於表長,放乙個元素時,若發生衝突,則順次線性掃瞄直到找到乙個空位。2....

資料結構 雜湊

關鍵 不比較關鍵碼,直接搜尋得到需要的數。特點 與搜尋樹不一樣,雜湊結構元素的儲存位置與關鍵碼直接對應,可以不用進行比較遍歷。如圖,建立乙個陣列,把a 4 中的資料按特定的規則儲存到相應的位置,比如a i n,到時候搜尋資料的時候可以按照同樣的規律直接找到這個位置,如果這個位置有數,則存在。比如按照...