淺談哈希表和解決哈希衝突的幾種方法

哈希表也叫散列表

它的底層是通過數組也存儲元素的,他裏面有個hash函數,將一個key傳給hash函數,他會利用這個key生成這個key對應的索引,他的複雜度是O(1),所以得用哈希表來去完成映射的添加,搜索,刪除的話,總的來說時間複雜度是O(1)級別的.

hash函數也叫散列函數

哈希表內部的數組元素,很多地方也叫Bucket(桶),整個數組叫個Buckets或者BucketArray

哈希衝突--也叫哈希碰撞

就是二個不同的key,經過哈希函數,計算出相同的結果.

解決方法:

1 開放定址法:按照一定規則向其它地址探測,直到遇到空桶.比如線性探測,假如現在的索引是3,3有值就向4探測,如果還有就繼續向下,還比如平方探測.就是1 2 3 ...的平方進行探測.

2:再哈希法,設計多個哈希函數

3:鏈地址法,HashMap就是這樣操作的

 

JDK1.8是怎麼解決哈希衝突的

默認使用的是單身鏈表將元素串起來

在添加元素時,可能會由單向鏈表轉爲紅黑樹來存儲元素

比如當哈希表的容量>=64且單向鏈表的節點數量大於8時就會由單向鏈表轉爲紅黑樹來存儲元素

當紅黑樹節點數量少到一定程度時,又會轉爲單向鏈表

所以JDK1.8中的哈表是由鏈表加上紅黑樹來解決衝突的.

 

爲會麼使用單向鏈表而不用雙向

1.當哈希衝突的時候會往鏈表尾部裏添加節點,爲什麼添加到尾部,是因爲當衝突的時候它要在鏈表裏不斷對比key是不是一樣,所以要一直對比下去,找到了就替換沒有找到就添加到尾部.

2.單鏈表比雙鏈表少一個指針,可以節省內存空間

 

哈希函數中實現步驟是怎樣的(hashCode)

1:先生成key的哈希值,必須是整數

2:讓這個哈希值跟數組的大小進行相關運算,生成一個索引值.(hashCode(key)%table.length)

    2.1:爲了提高效率,官方是通過&運算來取代%運算的,前提是數組的長度必須設計爲2的冪

    2.2:&運算的特點,二個都爲1結果才爲1,其它都爲0;(hashCode(key)&(table.length-1))

    2.3:爲什麼要-1,因爲長度爲2的的冪,比如16二進制就是10000,減一個1就變成了01111,這個時候通過hash值來跟01111做&運算的話得出的結果必然是小於等於01111.比如算出的hash值爲1000101010 這個時候table的長度爲01111這個時候算出來的值就是1010.肯定不會超過數組的長度-1;

 

良好的哈希函數設計:讓哈希值更加均勻分佈 ,減少哈希衝突次數 ,從而提高哈希表的性能

如果生成key的哈希值

key的種類常見的有:整數,浮點數,字符串,自定義對象,不同種類的key哈希值生成的方式不一樣,但目標是一致的,儘量讓每個key的哈希值是唯一的,儘量讓Key的所有信息參加運算.

在Java中的Hashmap的Key必須實現hashCode,equals方法,也允許key爲null

整數: 直接把整數當哈希值

浮點數:Float.floatToIntBits(float),將浮點數轉爲int.將存儲的二進制轉爲整數

Long: Long是8個字節佔64位 官方算法是((int)(value^(value>>>32)))意思就是先將Long類型的value無符號右移32位,再和value做^運算,就是高32位和低32位混合在一起計算出哈希值.強制轉換成int就是把高32位給忽略掉

^運算(異或):相同爲0不同爲1----    |或運算: 有1個爲1就是1

Double: 就是將Double先轉爲Long,然後操作跟Long一樣

字符串: 遍歷字符串每次都要執行這個行代碼hashcode= hashcode*31+char(遍歷出來的)  31=(2>>5)-1

Object(自定義對象): 如果不重寫hashCode方法,則是用內存地址來計算的,如果有特殊需求則可以重寫hashCode方法,但是最好利用自定義對象裏所有成員變量來計算hashCode值.比如自定義一個Person對象,裏面有age,height,name則可以這樣寫

int hashCode = Integer.hashCode(age);

hashCode = hashCode*31+Float.hashCode(height);

hashCode = hashCode*31+(name!=null)?name.hashCode():0);

return hashCode;

如果自己實現了hashCode方法,最好複寫equals方法,用於判斷key是不是同一個key但是要遵循幾個準則

1.必須保證equals方法爲true的那麼他們的hashCode必須要相等

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章