之前我們講到過線性表、有序表、索引表、樹的查找,通過將無序的集合轉為上述的結構可以實現(xiàn)查找功能。那么現(xiàn)在要用的就是散列表來查找數據,優(yōu)勢是能夠直接找到記錄地址不需要花時間查找,但是只適合與給定值相等的記錄
散列技術
定義:散列技術是在記錄的存儲位置和它的關鍵字之間建立一個確定的對應關系f,使得每個關鍵字key對應一個存儲的位置 f(key)
要理解散列技術就必須先理解之前我們是怎么找到數據記錄的。
非散列表查找:
用戶輸入關鍵字 ——> 找到關鍵字 ——> 找到和關鍵字存在一起的記錄地址——> 找到數據記錄
- 關鍵字和數據記錄地址是兩個內存空間,一般是連續(xù)的,此時記錄地址是真實存在內存里的
- 最花時間的是如何找到關鍵字
散列表查找:
用戶輸入關鍵字 ——> 把關鍵字代入函數 ——> 計算得出記錄地址 ——> 找到數據記錄
- 我既不需要再一堆關鍵字里面找到用戶輸入的關鍵字
- 也不需要把記錄地址存在內存里
- 就是通過一條對關鍵字的計算公式得到記錄地址
散列技術就是,建立一個把關鍵字作為自變量,記錄地址作為因變量的函數,也就是說它的核心就是函數關系,至于自變量和因變量是什么,都不太重要
散列函數(哈希函數)、散列表(哈希表)
捋一下這幾個概念:
散列函數,也稱哈希函數,代表關鍵字和記錄地址的對應關系f
散列表,也稱哈希表,表示的是采用散列技術將記錄存儲在的一塊連續(xù)的存儲空間——即為數據記錄本身存的地方
散列技術適合什么問題?
所謂查找給定值相等的記錄就是,我給什么值,就找到它的那條唯一記錄。
而不是一個定值有很多條對應的記錄(例如給“男”這一定值,查找班里的人,會發(fā)現(xiàn)有很多記錄,也就是說給定的值不能是次關鍵字),或者說是范圍性的查找
散列函數
散列函數的作用就是起一個映射關系,最理想的散列函數能夠使得計算過程簡單、散列地址分布均勻(為了盡最大努力減少沖突)
下面方法都可以從五方面來考慮他們的優(yōu)劣:
- 計算散列地址所需要的時間(計算方法復不復雜?)
- 關鍵字長度(普遍位數的是比較多?關鍵字與關鍵字長度差別較大?)
- 散列表的大小
- 關鍵字的分布情況(分布是否均勻?)
- 記錄查找的頻率(查找是否頻繁?)
1.直接定址法
直接把關鍵字與其他常數進行簡單運算得到地址
2.數字分析法
它關鍵點在于:抽取
數字分析法就是從關鍵字中抽取出某個部分作為記錄地址
3.平方取中法、折疊法
都是對關鍵字進行變換的方法,這兩種方法的效果是:對關鍵字位數進行增減之后抽取幾位作為記錄地址
4.除留余數法
(常用mod方法來控制事物如果超過一定長度后進行輪回)
在這里,通過對關鍵字取模來映射,那么地址就不會大于所設定的模的數。
5.隨機數法
f(key) = random(key),雖然這里的random是隨機函數,但是它是偽隨機的——同樣的隨機種子會有同樣的值
解決沖突的辦法
解決沖突就是為了讓兩個本要存同一個地址的數據都能被找到不覆蓋彼此,辦法有
- 開放定址法、再散列法(探測空的位置)
思路:如果沖突,探測找到一個空的位置,把數據放到這個位置。探測的方法有幾類:線性探測(找下一個空的位置)、二次探測(往前往后替換找空的位置)、隨機探測(random函數)、換一個散列函數再嘗試(再散列的方法,再散列不是指二次散列,而是上一個散列函數計算出來的沖突了,那么換一個新的散列函數重新嘗試,自變量都是放原來的key)
- 鏈地址
思路:不換地址,既然沖突了就放在一起,通過鏈表的形式
image.png - 公共溢出區(qū)
思路:既然沖突了,那么就統(tǒng)一把沖突的放到一個地方,在散列表里面找不到就在這里找
散列表的操作
散列表是一種新的數據結構,它的特點是怎么存的我就怎么找,存儲和查找的方法都是相同的,因此我們存的時候使用上面哪一種散列函數和沖突解決辦法,在查找關鍵字的時候也是用同樣的方法。
平均查找的長度取決于裝填因子,而不取決于查找集合中記錄個數
裝填因子α=已填入表中個數/散列表長度。它標志著散列表的裝滿程度,裝得越多當然沖突的可能就越大啦。如果使得裝填因子較小,那就是一個利用空間換時間的例子了。