HashTable

哈希表是一個(gè)數(shù)據(jù)結(jié)構(gòu),用于映射鍵值(也稱為Table或Map抽象數(shù)據(jù)類型/Abstract Data Type,ADT)。
它使用一個(gè)散列函數(shù)將大的或甚至非整數(shù)的鍵映射到一個(gè)小范圍的整數(shù)索引(通常是[0..hash_table_size-1])。

兩個(gè)不同的鍵碰撞到同一個(gè)索引中的概率相對較高,每一個(gè)潛在的沖突都需要解決,以保持?jǐn)?shù)據(jù)的完整性。

  • 哈希是一種算法(通過一個(gè)哈希函數(shù)),該算法將可變長度的大數(shù)據(jù)集(稱為鍵,不一定是整數(shù))映射為一個(gè)固定長度的較小整數(shù)數(shù)據(jù)集。
  • 哈希表是一種數(shù)據(jù)結(jié)構(gòu),它使用哈希函數(shù)有效地映射鍵值(Table或Map ADT),以便進(jìn)行有效的搜索/檢索、插入和/或刪除。
  • 哈希表被廣泛應(yīng)用于各種計(jì)算機(jī)軟件,特別是關(guān)聯(lián)數(shù)組、數(shù)據(jù)庫索引、緩存和集合。

在這個(gè)e-Lecture中,我們將離題到表ADT,哈希的基本思想,哈希函數(shù)的討論,然后再討論哈希表數(shù)據(jù)結(jié)構(gòu)本身的細(xì)節(jié)。

Table ADT必須至少支持以下三種操作:

  • search(v) 確定是否存在于ADT中,
  • insert(v) 插入vADT,
  • delete(v)ADT中移除v。

哈希表是這個(gè)Table ADT的一個(gè)可能的良好實(shí)現(xiàn)。

PS:對于Table ADT的兩個(gè)較弱的實(shí)現(xiàn),可以點(diǎn)擊各自的鏈接:
未排序的數(shù)組已排序的數(shù)組來讀取詳細(xì)的討論。


當(dāng)整數(shù)鍵的范圍很小的時(shí)候,例如[0..M-1],我們可以使用一個(gè)初始為空的大小為M的Boolean類型的數(shù)組A,并直接實(shí)現(xiàn)如下Table ADT操作:

  • search(v) 檢查A[v]是否為true(filled)或false(empty),
  • insert(v) 設(shè)A[v]為真(填充),
  • delete(v) 設(shè)置[v]為false(空)。

就是這樣,我們使用小整數(shù)鍵本身來確定數(shù)組A中的地址,因此名稱直接尋址。顯然,所有三個(gè)主要的Table ADT操作都是O(1)


在新加坡(截至2018年3月),公交路線編號從[2..990]。

當(dāng)前并不是所有的[2..990]之間的整數(shù),例如,沒有公交線路989 - 搜索(989)應(yīng)返回false??梢砸胄碌墓财嚶肪€x,即insert(x),或現(xiàn)有的公共汽車路線y不再使用,即remove(y)。

由于可能的公交路線的范圍很小,為了記錄數(shù)據(jù)是否存在公交線路號碼,我們可以使用具有1000大小的布爾數(shù)組的DAT。

討論:在現(xiàn)實(shí)生活中,我們可以討論為什么我們使用1000而不是990(或991)。


請注意,我們總是可以添加衛(wèi)星數(shù)據(jù),而不是使用Boolean數(shù)組來記錄鍵key的存在。

例如,我們可以使用一個(gè)關(guān)聯(lián)的字符串?dāng)?shù)組A來代替一個(gè)公交路線號碼映射到它的運(yùn)營商名稱,例如,

A[2] = "Go-Ahead Singapore"
A[10] = "SBS Transit"
A[183] = "Tower Transit Singapore"
A[188] = "SMRT Buses"
etc..

鍵必須是(或可以輕松映射到)非負(fù)整數(shù)值。

基本的DAT在前面例子中存在問題,因?yàn)閷?shí)際上新加坡的公交路線號有變化,并不是純數(shù)字,例如, 96B,151A,NR10等。

鍵的范圍必須很小。
如果我們有(十分瘋狂的)大范圍的話,內(nèi)存使用量會(十分瘋狂地變得)很大。

鍵必須密集,即鍵值中沒有太多空白。
否則DAT將包含太多的空單元。

我們將用哈希來克服這些限制。

使用哈希,我們可以:

  • 將(一些)非整數(shù)的鍵映射到整數(shù)鍵,
  • 將大的整數(shù)映射到較小的整數(shù),
  • 影響哈希表的密度或負(fù)載因子α= N / M,其中N是鍵的數(shù)量,M是哈希表的大小。

例如,我們有N = 400個(gè)新加坡電話號碼(新加坡電話號碼有8位數(shù)字,所以在新加坡可能有10 ^ 8 = 100M的電話號碼)。

我們可以使用以下簡單的哈希函數(shù)h(v) = v % 997來代替使用DAT并使用大小為 M = 1億的巨大數(shù)組。

這樣,我們將8位電話號碼6675 23786874 4483分別映射到最多3位數(shù)字h(6675 2378) = 237h(6874 4483) = 336。因此,我們只需要準(zhǔn)備大小為M = 997(或1000)的數(shù)組而不是M = 1億。

使用散列(hashing),我們現(xiàn)在可以使用Integer數(shù)組(而不是布爾數(shù)組)執(zhí)行下面的表ADT操作,如下所示:

search(v)檢查A [h(v)]!= -1(假設(shè)v≥0,我們對空單元使用-1)
insert(v) 設(shè)置A [h(v)] = v(我們把v散列到h(v)中,所以我們需要以某種方式記錄密鑰v),
delete(v) 設(shè)置A [h(v)] = -1 - 將進(jìn)一步闡述。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容