Java集合--Hash、Hash衝突

來源:互聯網
上載者:User

標籤:擴容   身高   頻繁   連續序列   維護   符號   拉鏈法   static   方法   

一、Hash

  散列表(Hash table,也叫雜湊表),是根據鍵(Key)而直接存取在記憶體儲存位置的資料結構。也就是說,它通過計算一個關於索引值的函數,將所需查詢的資料對應到表中一個位置來訪問記錄,這加快了尋找速度。 這個映射函數稱做散列函數,存放記錄的數組稱做散列表。

  • 實現Hash演算法的關鍵:實現hash演算法 、解決hash衝突
1.Hash函數

  首先來說hash函數,java中對象都已一個hashCode()方法,那為什麼還需要hash函數呢?hashCode是在jdk中是有符號int類型,這個一個很大的範圍,如果散列表的數組能覆蓋所有int值的話,就不需要hash函數了,當然記憶體不允許我們維護這麼大的散列表。這時我們需要hash函數將原始hashCode映射到一個很小的數組上去。意思就是將超大超長或不定長的整形資料轉換為唯一(理想情況,對於不同對象hash值應該不相同)的定長的hash值,常見的做法是模數法,也是jdk中的實現方式。

  • HashMap的hashCode實現:
1 static final int hash(Object key) {2     int h;3     return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);4 }5 6 static int indexFor(int h, int length) {7     return h & (length-1);8 }

  第一個hash函數有人稱之為“擾動函數”,第二個indexFor函數在jdk8中去掉了,函數內的代碼合并到了putVal中,個人認為這兩個函數合并起來是一個完整的hash函數。
  h & (length-1) 這段代碼的作用其實就是模數,假設數組初始化長度為16,那麼length-1的結果為15,對應二進位為00001111,如果我們有一個大小為20的key,對應二進位為00010100,與運算後結果為00000100,對應十進位為4。
  這裡數組的長度必須為2的次冪。由於對key進行了模數運算,所以我們知道當length=16的時候,我們會捨棄調掉key高位的值,只保留了低4位。本來int是32位,只是用低4位衝突是不是太容易發生了?
  所以第一個“擾動函數”的作用出現了,這個函數將key本身高16和低16位做了異或運算。

  儘管實現了如此有效散列演算法,但只是將不同對象之間hash碰撞的機率降低了,還是不能完全保證不發生hash衝突,因此要繼續使用hash表的優點就要解決hash衝突的問題。

二、解決Hash衝突1.開放定址法(線性探測,二次探測,偽隨機探測)

  用開放定址法解決衝突的做法是:當衝突發生時,使用某種探查(亦稱探測)技術在散列表中形成一個探查(測)序列。沿此序列逐個單元地尋找,直到找到給定的關鍵字,或者碰到一個開放的地址(即該地址單元為空白)為止(若要插入,在探查到開放的地址,則可將待插入的新結點存人該地址單元)。尋找時探查到開放的 地址則表明表中無待查的關鍵字,即尋找失敗。

  當雜湊表越來越滿時聚集越來越嚴重,這導致產生非常長的探測長度,後續的資料插入將會非常費時。通常資料超過三分之二滿時效能下降嚴重,因此設計雜湊表關鍵確保不會超過這個資料容量的一半,最多不超過三分之二。

  • 用開放定址法建立散列表時,建表前須將表中所有單元(更嚴格地說,是指單元中儲存的關鍵字)置空。
  • 空單元的表示與具體的應用相關。

  按照形成探查序列的方法不同,可將開放定址法區分為線性探查法、線性補償探測法、隨機探測等。

(1)線性探查法(Linear Probing)

  • 該方法的基本思想是將散列表T[0..m-1]看成是一個迴圈向量,若初始探查的地址為d(即h(key)=d),則最長的探查序列為:

d,d+l,d+2,…,m-1,0,1,…,d-1
  即:探查時從地址d開始,首先探查T[d],然後依次探查T[d+1],…,直到T[m-1],此後又迴圈到T[0],T[1],…,直到探查到T[d-1]為止。

  • 探查過程終止於三種情況:

  ①若當前探查的單元為空白,則表示尋找成功(若是插入則將key寫入其中);
  ②若當前探查的單元中含有key,則尋找成功,但對於插入意味著失敗;
  ③若探查到T[d-1]時仍未發現空單元,則無論是尋找還是插入均意味著失敗(此時表滿,需要擴容)。

  • 利用開放地址法的一般形式,線性探查法的探查序列為:

hi=(h(key)+i)%m 0≤i≤m-1 //i=1

  • 用線性探測法處理衝突,思路清晰,演算法簡單,但存在下列缺點:

  ①雜湊表容量不能完全利用,並且擴容將會是災難的,需要刪除以前標記過的元素並需要從新計算所有元素的位置,在頻繁的刪除和插入時效率變得很低。
  ②按上述演算法建立起來的雜湊表,刪除工作非常困難。假如要從雜湊表 HT 中刪除一個記錄,按理應將這個記錄所在位置置為空白,但我們不能這樣做,而只能標上已被刪除的標記,否則,將會影響以後的尋找。
  ③線性探測法很容易產生堆聚現象。所謂堆聚現象,就是存入雜湊表的記錄在表中連成一片。按照線性探測法處理衝突,如果產生雜湊地址的連續序列愈長(即不同關鍵字值的雜湊地址相鄰在一起愈長),則當新的記錄加入該表時,與這個序列發生衝突的可能性愈大。因此,雜湊地址的較長連續序列比較短連續序列生長得快,這就意味著,一旦出現堆聚(伴隨著衝突),就將引起進一步的堆聚。

(2)線性補償探測法

  線性補償探測法的基本思想是將線性探測的步長從 1 改為 Q ,即將上述演算法中的 hi=(h(key)+i)%m改為:hi=(h(key)+Q)%m,這個Q是根據一定的增長率變化的(1、4、9...),這樣使得資料分布的足夠散亂,不容易出現聚堆現象,而且要求 Q 的變化能使全表得到完整的掃描,以便能探測到雜湊表中的所有單元(當然還有其他的線性在散列演算法規則,這裡只討論該種方式的再散列)。

(3)隨機探測

  隨機探測的基本思想是將線性探測的步長從常數改為隨機數,即令:hi=(h(key)+RN)%m ,其中 RN 是一個隨機數。在實際程式中應預先用隨機數發生器產生一個隨機序列,將此序列作為依次探測的步長。這樣就能使不同的關鍵字具有不同的探測次序,從而可以避免或減少堆聚。基於與線性探測法相同的理由,線上性補償探測法和隨機探測法中,刪除一個記錄後也要打上刪除標記。

2.鏈地址法(拉鏈法)

  拉鏈法解決衝突的做法是將所有關鍵字為同義字的結點連結在同一個單鏈表中。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指標組成的指標數 組T[0..m-1]。凡是散列地址為i的結點,均插入到以T[i]為頭指標的單鏈表中。T中各分量的初值均應為空白指標。在拉鏈法中,裝填因子α可以大於 1,但一般均取α≤1。

  • 與開放定址法相比拉鏈法的優點

  ①拉鏈法處理衝突簡單,且無堆積現象,即非同義字決不會發生衝突,因此平均尋找長度較短;
  ②由於拉鏈法中各鏈表上的結點空間是動態申請的,故它更適合於造表前無法確定表長的情況;
  ③開放定址法為減少衝突,要求裝填因子α較小,故當結點規模較大時會浪費很多空間。而拉鏈法中可取α≥1,且結點較大時,拉鏈法中增加的指標域可忽略不計,因此節省空間的;
  ④在用拉鏈法構造的散列表中,刪除結點的操作易於實現。只要簡單地刪去鏈表上相應的結點即可。而對開放地址法構造的散列表,刪除結點不能簡單地將被刪結 點的空間置為空白,否則將截斷在它之後填人散列表的同義字結點的尋找路徑。這是因為各種開放地址法中,空地址單元(即開放地址)都是尋找失敗的條件。因此在 用開放地址法處理衝突的散列表上執行刪除操作,只能在被刪結點上做刪除標記,而不能真正刪除結點。

  • 拉鏈法的缺點

  當發生hash衝突時,需要產生鏈表由此需要額外佔用空間,並且需要花一定的時間和精力維護衝突鏈表。在擴容的時候需要把所有元素進行重新hash並分配地址,演算法較為複雜繁瑣。

3.再雜湊(瞭解)

  再hash法,就是算hashcode的方法不止一個,一個要是算出來重複啦,再用另一個演算法去算。使用一定的演算法邏輯的到一種在當前情況不會發生hash衝突的hash演算法。

4.建立公用溢出區(瞭解)

  建立一個公用溢出地區,就是把衝突的都放在另一個地方,不在表裡面。具體實現不做探討了(不常用)。

Java集合--Hash、Hash衝突

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.