資料結構 關於雜湊表

2021-07-27 05:40:31 字數 4372 閱讀 5743

學習完二叉搜尋樹後,我們來學習一種新的結構,雜湊表

二叉搜尋樹具有lgn的搜尋時間複雜度,但是是建立在資料有足夠的隨機性

雜湊表是也是具有對數時間複雜度的,但是它是以統計為基礎的,並不在乎輸入資料的隨機性

*hashtable-雜湊表/雜湊表,是根據關鍵字(key)而直接訪問在記憶體儲存位置的資料結構。

*它通過乙個關鍵值的函式將所需的資料對映到表中的位置來訪問資料,這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表。

*雜湊表可以看作是字典結構,它操作的是有名項,提供常數時間的基本操作

1)直接定址法: 該方法是取關鍵字的某個線性函式值為雜湊位址 

2)除留餘數法: 它是用資料元素關鍵字除以某個常數所得的餘數作為雜湊位址。 

3)摺疊法:將關鍵字分割成位數相同的幾部分,最後一部分位數可以不同,然後取這幾部分的疊加和(去除進製)作為雜湊位址。數字疊加可以有移位疊加和間界疊加兩種方法。 

4)隨機數法::選擇一隨機函式,取關鍵字的隨機值作為雜湊位址,通常用於關鍵字長度不同的場合。 

5)*數學分析法:找出數字的規律,盡可能利用這些資料來構造衝突機率較低的雜湊位址。

一般常用的方法是直接定址法和除留餘數法。

取關鍵字的某個線性函式為雜湊位址,hash(key)= key 或 hash(key)= a*key + b,a、b為常數。

當我們通過雜湊函式進行對映的時候,不同的鍵值會對映到同乙個位置

我用圖示說明下:

先介紹乙個概念

:負載因子

雜湊表的負載因子

:x = 填入表中的元素的個數/雜湊表的長度

說明:a:x是雜湊表裝滿程度的標誌因子。由於表長是定值,x與「填入表中的元素個數」成正比,所以,x越大,表明填入表中的元素越多,產生衝突的可能性就越大;反之,x越小,標明填入表中的元素越少,產生衝突的可能型就越小。

b:對於開放定址法,負載因子是特別重要的因素,一般嚴格限制在0.7-0.8以下。超過0.8,查表時的cpu快取不命中按照指數曲線上公升。因此,一些採用開放定址法的hash庫,超過的話,就進行resize雜湊表。

c:要進行說明的乙個關於負載因子的悖論,既然負載因子是這樣的話,那麼我們可以將負載因子設的小一點,這樣的話,效率就會很高,但是這樣同時會很浪費空間,所以其實這裡面也是相互制約的。

a:線性探測:

線性探測就是當你插入乙個數的位置有衝突了,那麼這個時候,你就向後找,找到乙個空的沒有元素插入的位置進行插入。

b:二次探測:

是用來解決線性探測的問題的,由於線性探測在進行插入的時候,如果插入到大於負載因子的值時,就要進行擴容。下面我來用**說明下二次探測的做法:

為了讓雜湊表更加高效,人們又想出了一種解決雜湊衝突的辦法,就是雜湊桶,這種方法簡單的來說就是:順序表和煉表的結合,順序表就像是乙個指標陣列,在這個陣列中每乙個指標底下都掛著乙個桶,而這個桶就是由乙個乙個的節點構成。我用圖示進行說明下:

*雜湊桶的實現:

說明:當衝突比較大的時候底下用紅黑樹實現效率比較高

a:節點的定義:

//節點的定義

templatestruct hushnode

};

說明:這裡我們可以將節點定義成pair型別的,這樣當我們在實現迭代器的時候就會很方便,這個在後面我實現迭代器的時候再進行說明下。b:插入函式的實現:

//插入函式的實現

pairinsert(const k& key, const v& value)

node* temp = new node(key,value);

temp->_next = _ht[index];

_ht[index] = temp;

return make_pair(temp,true);

}

c:刪除函式的實現:

說明:在刪除的時候,我們要定義兩個指標,乙個是要刪除的節點,乙個是要刪除的指標的頭乙個節點,進行分析情況:

*如果要刪除的節點的前乙個節點為空的話:

那麼我們就讓要被刪除的這個節點的下乙個節點直接指向這個位置

*如果要刪除的節點的前乙個節點不為空的話:

那麼我們就讓要被刪除的節點的頭乙個節點的下乙個指標直接指向被刪除的節點的下乙個指標

void erase(const k& key)

else

cur = cur->_next;

} }

d:查詢函式的實現:

node* find(const k& key)

}return null;

}

e:析構函式的實現:

~hushtable()}}

【小擴充套件】:

當我們在考慮這塊的刪除的時候,我們可以可能會想到用find函式,如果用find的話,此時我們就要用交換的思想(因為此處就類似於單鏈表,只有向後的節點沒有向前的節點),但是還會有問題,如果刪除的是乙個沒有下乙個節點的節點,比如這裡的106,那麼我們此時就將0,這個位置和106進行交換,這樣就可以解決,如果刪除的是只有乙個節點的,刪除完後記得將此節點置為空。

說明:使用素數作為除數可以減少雜湊衝突

素數表的實現:

size_t getnewsize()

; for (size_t i = 0; i < _primesize; ++i)

}return 0;

}

//表中儲存元素的狀態

enum status

;templatestruct hashnode

};

bool insert(const k& key,const v& value)

++_size;

_ht[index]._key = key;

_ht[index]._value = value;

_ht[index]._status = exist;

return true;

}

//尋找元素的函式

node* find(const k& key)

return null;

}

//擴容函式

void checkcapacity()

this->swap(temp);

} }

//交換函式

void swap(hashtable& spht)

ptr operator->(node* node)

bool operator==(const self& s)

bool operator!=(const self& s)

self& operator++()

c:關於過載++的重點說明:

我們單獨實現乙個函式:next

*當下乙個節點不為空的時候我們就直接返回

*否則,我們就進行搜尋下乙個不為空的節點

node* next(node* node)

}return null;

}

1)說明:

我們在實現雜湊表的時候不一定就是整型,也可能是字串或者是結構體等等,那麼我們這裡就要進行這個方面問題的解決。這裡我們就利用仿函式進行實現,然後利用函式模板的特化

2)有關**:

//仿函式的實現

templatestruct _hashfunc

};template<>

struct _hashfunc

return hash;

} size_t operator ()(const string &key)

};

//雜湊函式(雜湊函式)

size_t _hashfunc(const k& key)

3)此處涉及到字串雜湊演算法

這個鏈結裡有詳細的解釋:

資料結構 雜湊表

1.雜湊表的定義 元素的儲存位置和它的關鍵碼之間建立乙個確定的對應關係h,使得每個關鍵碼key和唯一的儲存位置h key 相對應。在查詢時,根據這個確定的對應關係找到給定值k的對映h k 若查詢集合中存在這個記錄,則必定在h k 的位置上,這種查詢技術稱為雜湊技術。採用雜湊技術將記錄儲存在一塊連續的...

資料結構 雜湊表

雜湊表的定義 雜湊表 hash table,也叫雜湊表 是根據關鍵碼值 key value 而直接進行訪問的資料結構。也就是說,它通過把 關鍵碼值對映到表中乙個位置來訪問記錄,以加快查詢的 速度。這個對映函式叫做雜湊函式,存放 記錄的陣列叫做雜湊表。雜湊函式的析構方法 餘數法 取關鍵字被某個不大於雜...

資料結構 雜湊表

3 雜湊函式 數字分析法 根據關鍵碼在各個位上的分布情況,選取分布比較均勻的若干位組成雜湊位址。適用情況 能預先估計出全部關鍵碼的每一位上各種數字出現的頻度,不同的關鍵碼集合需要重新分析。4 雜湊函式 平方取中法 對關鍵碼平方後,按照雜湊表大小,取中間的若干位作為雜湊位址 平方後擷取 適用情況 實現...