数据结构与算法笔记(十五)—— 散列(哈希表)
一、前沿
1.1、直接尋址表
當關鍵字的全域U比較小時,直接尋址是一種簡單而有效的技術。假設某應用要用到一個動態集合,其中每個元素都有一個取自全域U={0,1,…,m-1)的關鍵字,此處m是一個不很大的數。另假設沒有兩個元素具有相同的關鍵字。
為表示動態集合,我們用一個數組(或稱直接尋址表)T[0…m一1],其中每個位置(或稱槽)應全域U中的一個關鍵字。下圖說明這個方法;槽 k 指向集合中一個關鍵字為 k 的元素。如果該集合中沒有關鍵字為 k 的元素,則T[k]=NIL。
用一個直接尋址表T實現動態集合。全域U={0,1,…,9}中的每個關鍵字都對應于表中的一個下標值。由實際關鍵字構成的集合K={2,3,5,8}決定表中哪些槽包含指向元素的指針。其他帶深陰影的槽包含NIL
直接尋址技術缺點:
- 當域U很大時,需要消耗大量內存,很不實際
- 如果域U很大而實際出現的key很少,則大量空間被浪費
- 無法處理關鍵字不是數字的情況
1.2、哈希
直接尋址表:key為k的元素放到k位置上
改進直接尋址表:哈希(Hashing)
- 構建大小為m的尋址表T
- key為k的元素放到h(k)位置上
- h(k)是一個函數,其將域U映射到表T[0,1,…,m-1]
二、哈希表
2.1、概念
哈希表(Hash Table,又稱為散列表),是—種線性表的存儲結構。哈希表由一個直接尋址表和一個哈希函數組成。哈希函數h(k)將元素關鍵字k作為自變量,返回元素的存儲下標。
哈希表一個通過哈希函數來計算數據存儲位置的數據結構,通常支持如下操作:
- insert(key,value):插入鍵值對(key,value)
- get(key):如果存在鍵為key的鍵值對則返回其value,否則返回空值
- delete(key):刪除鍵為key的鍵值對
例:假設有一個長度為7的哈希表,哈希函數h(k)=k%7。元素集合{14,22,3,5}的存儲方式如下圖:
2.2、哈希沖突
由于哈希表的大小是有限的,而要存儲的值的總數量是無限的,因此對于任何哈希函數,都會出現兩個不同元素映射到同一個位置上的情況,這種情況叫做哈希沖突。
2.2.1、解決哈希沖突——開放尋址法
開放尋址法:如果哈希函數返回的位置已經有值,則可以向后探查新的位置來存儲這個值
- 線性探查:如果位置i被占用,則探查i+1, i+2,…
- 二次探查:如果位置i被占用,則探查i+1^2, i-1^2, i+2^2, i-2^2,…
- 二度哈希:有n個哈希函數,當使用第1個哈希函數h1發生沖突時,則嘗試使用h2,h3,…
2.2.2、解決哈希沖實——拉鏈法
拉鏈法:哈希表每個位置都連接—個鏈表,當沖突發生時,沖突的元素將被加到該位置鏈表的最后。
2.3、常見哈希函數
除法哈希法
乘法哈希法
全域哈希法
三、哈希表實現(拉鏈法)
鏈表代碼(單鏈表):數據結構與算法筆記(三)—— 鏈表(單鏈表、循環鏈表、雙向鏈表)
class HashTable:def __init__(self,size = 20):self.size = sizeself.T = [SingleLinkList() for i in range(self.size)]def h(self,k):'''哈希函數: 計算數據存儲位置'''return k % self.sizedef insert(self,k):'''插入元素'''i = self.h(k)if self.find(k):print('重復插入!!!')else:self.T[i].append(k)def find(self,k):'''查找元素'''i = self.h(k)return self.T[i].search(k)def travel(self):'''遍歷打印'''for i in range(self.size):print(self.T[i].travel())def remove(self,k):'''刪除元素'''if self.find(k):i = self.h(k)self.T[i].remove(k)if __name__ == '__main__':ht = HashTable()ht.insert(0)ht.insert(1)ht.insert(2)ht.insert(21)ht.travel()ht.remove(2)ht.travel()print(ht.find(2))四、哈希表的應用
4.1、集合與字典
字典與集合都是通過哈希表來實現的。
例如:
a = {'name': 'Alex', 'age': 18, 'gender': 'Man'}使用哈希表存儲字典,通過哈希函數將字典的鍵映射為下標。
假設:
則哈希表存儲為
[None,18,None,'Alex','Man']如果發生哈希沖突,則通過拉鏈法或開發尋址法解決
4.2、md5算法
MD5(Message-Digest Algorithm 5)曾經是密碼學中常用的哈希函數,可以把任意長度的數據映射為128位的哈希值,其曾經包含如下特征:
應用舉例: 文件的哈希值
算出文件的哈希值,若兩個文件的哈希值相同,則可認為這兩個文件是相同的,因此:
4.3、SHA2算法
歷史上MD5和SHA-1曾經是使用最為廣泛的 cryptographic hash function,但是隨著密碼學的發展,這兩個哈希函數的安全性相繼受到了各種挑戰。
因此現在安全性較重要的場合推薦使用SHA-2等新的更安全的哈希函數。
SHA-2包含了一系列的哈希函數: SHA-224,SHA- 256,SHA-384,SHA-512,SHA-512/224,SHA- 512/256,其對應的哈希值長度分別為224,256,384 or 512位。
SHA-2具有和MD5類似的性質(參見MD5算法的特征)。
應用舉例:
例如,在比特幣系統中,所有參與者需要共同解決如下問題:對于一個給定的字符串U,給定的國標哈希值H,需要計算出一個字符串V,使得U+V的哈希值與H的差小于一個給定值D。此時,只能通過暴力枚舉V來進行猜測。首先計算出結果的人可獲得一定獎金。而某人首先計算成功的概率與其擁有的計算量成正比,所以其獲得的獎金的期望值與其擁有的計算量成正比。
總結
以上是生活随笔為你收集整理的数据结构与算法笔记(十五)—— 散列(哈希表)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构与算法笔记(十四)—— 二叉树
- 下一篇: 数据结构与算法笔记(十六)—— 二叉搜索