資料結構 雜湊表理解與實現

2021-08-14 22:16:01 字數 3589 閱讀 4256

一、雜湊表的簡介

1、在我們c++11中的unordered_set/unordered_map以及unordered_multiset/unordered_multimap底層最主要的實現就是雜湊表;而雜湊表則是通過關鍵字(key)按照一定的規律對映到表中的位置。

2、最常用構造雜湊表的方法:

<1>直接定址法:將關鍵字通過某個線性函式,算出在表中對應的下標;

<2>除留餘數法:取關鍵字%表長的餘數,作為下標,進行資料的寫入。

二、雜湊衝突

有了上面的介紹,應該知道大概是怎麼一回事了。也就是說,假如給我們乙個鍵值對,我們就需要利用key的數值按照一定的規律算出該資料在表中的下標,再進行寫入。但是會出現一種情況:比如我們按照除留餘數法,現在表長為10(下標為0~9);有兩個key值分別為11,21;計算出除留餘數的結果都是1,可是下標為1的位置卻只有乙個,那麼到底該誰寫入呢?這就是所謂的雜湊衝突問題。下面就重點介紹如何解決雜湊衝突問題。

<1>開放定址法。

開放定址法分類:1. 線性探測:假如key值對應算出下標為1,且該位置已經有元素,那麼就繼續向後探測,直到存在乙個位置沒有資料寫入。需要注意的是,當探測到表的最後乙個元素時,可將index置為0,再次從頭探測。

2. 二次探測:將現有的下標值每次挪動2的挪動次數次的次方;

<2>雜湊桶

在之前的結構中,我們總是將資料一直按照一定的規律,重新找到乙個位置將資料安置下來;但是在雜湊桶這種方法中,每個資料都儲存在他們算出來的下標中,只不過將表的結構改為了乙個指標陣列;每個元素底下都是一條鍊錶,將對應的元素鏈結起來。

<3>使用素數表

保證表的大小都為素數,可有效降低雜湊衝突。至於為什麼,如果有興趣可以自行查閱資料。下面的**中就使用了素數表,給定當前表的大小,返回比當前數大且最差最小的素數。
<4>控制負載因子
負載因子 = 填入表中的元素個數 / 表的長度;

其實也不難想到,負載因子越接近於0,說明空間浪費越大,但是衝突越小,也就是效率越高;反之同理。但是重要的就是負載因子應該控制到多少才好?一旦負載因子到達這個值,就進行擴容,在保證效率的同時也相對節省記憶體。

對於開放定址法,一般嚴格控制在0.7~0.8之間。

注:在雜湊桶中可能會出現一條支鏈的長度過長,影響搜尋效率;有些底層在遇到該類問題時,會將該支鏈構造為一棵紅黑樹,這樣就會縮小帶來的問題。

三、時間複雜度

對於一般的時間複雜度計算,我們都考慮的是最壞的情況,而在雜湊表中則不是,雜湊表查詢的時間複雜度為o(1);如此高的效率完全得益於對於結構的優勢以及一些情境下優化的保證。
接下來分別用**實現下開放定址法和雜湊桶。需要注意的點都在注釋中標出。
//開放定址法

#pragma once

#include

#include

using

namespace

std;

enum state

;template

struct hashnode

};//一些key值型別需要特殊處理

template

struct __hashfunc

};template

class hashtable

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

//找到位置

_tables[index]._key = key;

_tables[index]._value = value;

_tables[index]._state = exist;

_size++;

return

true;

}node* find(const k& key)

++index;

if (index == _tables.size())

index = 0;

}return

false;

}bool remove(const k& key)

return

false;

}protected:

//利用除留餘數法

size_t getindex(const k& key)

void checkcapacity()

else

if (_size * 10 / _tables.size() >= 7)

}_tables.swap(newtable._tables);}}

//取下乙個素數

size_t getnextprime(size_t size)

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

}return _primelist[_primesize - 1];}};

//雜湊桶

#pragma once

#include

using

namespace

std;

template

struct hashnode

};template

struct _hashfunc

};template

class hashbucket

void resize(size_t size)

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

//進行頭插

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

newnode->_next = _tables[index];

_tables[index] = newnode;

++_size;

return

true;

}node* find(const k& key)

return null;

}bool remove(const k& key)

//使用替代刪除法

while (cur)

else

}return

false;

}protected:

void checkcapacity()

}_tables.swap(newtable);}}

size_t getindex(const k& key, size_t size)

//素數表

size_t getnextprime(size_t size)

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

}return _primelist[_primesize - 1];

}size_t hashfunc(const k& key)

};

《C 實現資料結構》 雜湊表

雜湊表通過將關鍵字值對映到表中某個位置上來儲存元素。由給定的關鍵字值,根據對映,計算得到元素的儲存位置來訪問元素。在雜湊技術中,衝突是指對於關鍵字集合中的兩個關鍵字值ki和kj,當ki kj時,有h ki h kj h是雜湊函式。目前比較常用的雜湊函式有 除留餘數法 平方取中法 摺疊法 數字分析法。...

資料結構與演算法 雜湊表

對映在數學上相當於乙個函式f x a b。雜湊表的核心是乙個雜湊函式 hash function 這個函式規定了集合a中的元素如何對應到集合b中的元素。根據設定的雜湊函式 h key 和處理衝突的方法 將一組關鍵字映像到乙個有限的連續的位址集 區間 上,並以關鍵字在位址集中的 像 作為相應記錄在表中...

資料結構與演算法 雜湊表

雜湊表也叫雜湊表,hash表是一種根據關鍵字值 key value 而直接進行訪問的資料結構。是把記錄的儲存位置和記錄的關鍵字之間建立對應關係的一種儲存結構。雜湊表又叫 雜湊表,速度很快,最常用的一種儲存機構是順序表 鍊錶的結構 主結構是順序表,每個順序表中的元素又對應一張鍊錶。雜湊表的常用資料結構...