數據結構——散列表

什麼是散列表

       散列表也叫做哈希表(hash table),這種數據結構提供了鍵和值的映射關係。根據key可以快速的查找他所匹配的value,時間複雜度接近於O(1)。

散列表的實現

       散列表本質上就是一個數組,這也是爲啥散列表爲啥查找速度快。

       數組的下標是0,1,2,3....這樣的,散列表的key一般都是字符串類型的,所以我們需要一個“中轉站”,通過這個中轉站把key與數組下標進行轉換。這種中轉站就叫作哈希函數

       在java及大多數面向對象的語言中,每個 對象都有屬於自己的hashcode,無論對象自身的類型是什麼,他們的hashcode都是一個整型變量。既然是整型變量,想要轉換成數組下標就非常簡單了。最簡單的方法就是按照數組長度取模運算 ,也有利用位運算的方式來優化性能的。

散列表的讀寫操作

寫操作(put)

步驟:

        第一步:通過哈希函數,把key轉化成數組下標。

        第二步:如果轉換成的數組下標對應的位置沒有元素,就把這個鍵值對(不僅僅是value)填充到這個位置。

       在第二步中很可能出現一種情況,就是轉化的數組下標的地方已經存在元素的了,這種情況就叫作哈希衝突。哈希衝突是不可避免的,所以只能想辦法解決哈希衝突。解決哈希衝突主要有兩種方式:開放尋址法鏈表法

開放尋址法:

        開放尋址法的原理就是,當一個key通過哈希函數獲得對應的數組下標已被佔用時,我們可以“另謀高就”,尋找下一個空檔位置。

        尋址方式有很多種,並不是只有向後尋找一個元素這麼一種,但是大概原理都一樣。

鏈表法:

        這種方法的實現原理就是,數組中每個元素不僅僅是存的鍵值對對象,還是一個鏈表的頭節點。每個對象通過next指針指向他的下一個對象節點。當新來的鍵值對映射的下標產生衝突時,只需要插入到對應的鏈表即可。

讀操作(get)

步驟:

        第一步:通過哈希函數,把key轉化成數組下標。

        第二步:找到數組下標所對應的元素,如果這個元素的key是我們要讀取的,那麼就找到了;如果不是,就順着相應的鏈表往下找,找到與查找key對應的節點。

擴容(resize)

        因爲散列表本質就是數組,數組有一定的長度,長度不夠用需要擴容,所以哈希表也有擴容操作。散列表達到一定的飽和度(不同的地方定義不一樣)就需要擴容。

步驟:

        第一步:擴容,創建一個新的空數組,長度是原數組的2倍。

        第二步:重新Hash,遍歷原數組,把所有元素重新hash到新的數組中。

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