欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
《算法導論》讀書(shū)筆記7 (散列表)

《算法導論》第三部分 數據結構 略過(guò) 隊列 鏈表,我們到了 散列表

散列表是最常用的數據結構之一,特別是 ruby js等動(dòng)態(tài)語(yǔ)言在語(yǔ)法層次上對它進(jìn)行了支持。只是在java中,有那么點(diǎn)點(diǎn)繞(每次使用的時(shí)候,心里會(huì )疙瘩一下,不知道你們有沒(méi)有這種感覺(jué))。

本章真是糾結,因為看得懂的以前都看過(guò),不懂的現在還是看不懂。 還好看不懂的部分都是加星號的。

散列表是這樣一個(gè)東西:它能以key為索引保存東西, 然后在需要的時(shí)候嗖的一下就能找出來(lái),灰常地快:)

 

 get方法要在常量時(shí)間內找到需要的東西。O(1)  <--- 要這樣的復雜度

先不管這些,但至少HashTable看起來(lái)像這樣:

 

上面的代碼當然是通不過(guò)測試的(PS: 請先忘記java.util.HashTable)

要想get足夠快,那么最好是跟據 key 直接計算出存儲位置, 然后就能一下子找到啦。

差不多像這樣:

 

運行測試,數組越界, 因為我們還未實(shí)現 hash 這個(gè)方法。

hash 的作用是把關(guān)鍵字等可能地散列到 table 中去

除法散列,乘法散列,等等。

先試一個(gè)除法散列

 

capacity 不應該是 2 的冪, 否則的話(huà)值為hashCode的低 k 位, 高位就會(huì )浪費掉,可能會(huì )造成很多碰撞

可以選擇2的整數冪不大接近的質(zhì)數。

現在運行測試,是通過(guò)滴:)

但是等等, 有時(shí)候我們需要這樣:

Java代碼

  

我們需要重構代碼,把key也給保存起來(lái)。

首先添加一個(gè)結構, 保存key 和value

重構put

Java代碼
  1. public void put(String key, Object value) {   
  2.     int hash = hash(key.hashCode());   
  3.     if (table[hash] == null || table[hash].getKey().equals(key)) {   
  4.         table[hash] = new Entry(key, value);   
  5.     } else{   
  6.         throw new RuntimeException("撞車(chē)啦,怎么辦?");   
  7.     }   
  8. }  

 

重構get

 

 可以看到,測試又通過(guò)了:)

再看乘法散列

 

用常數(A) 乘hashCode  取小數 再乘capacity

Knuth認為 黃金分割數 是比較理想的值((根號5 - 1) / 2 ~ 0.618), 股民朋友們一定認識

乘法散列 的優(yōu)點(diǎn)是:

對 capacity 沒(méi)有什么特別的要求, 一般選擇它為 2 的整數冪。

因為這樣可以使用移位代替乘法計算。

然后黃金分割數 A 如果可以表示成 2654435769  / (2 ^32)

那就可以簡(jiǎn)化成:

              ((hashCode * 2654435769) 
                  & ((1 << 32) - 1) )   // 只保留 32 位
               >> (32 - p)

重購代碼試試看:

首先,數組空間大小為 2 ^ p

然后:

測試還是通過(guò)滴。

下面, 讓我們加多一點(diǎn)元素,搞壞它。

運行測試,失敗, 可以看到控制臺只輸出到 108

RuntimeException,   撞車(chē)了怎么辦?

可以采用鏈接法,開(kāi)放尋址法搞定

先來(lái) 鏈接法

首先重構Entry, 把自己串起來(lái)

 

同時(shí)也添加了一個(gè) setValue 方法, 這樣更容易在鏈表中“更新元素”

然后重構put

 

可以看到,測試正常運行:)

但是隨著(zhù)散列表中的元素越來(lái)越多,碰撞機率也越來(lái)越大,最好當元素數量達到一定量時(shí),自動(dòng)擴充容量,這樣才能保證其優(yōu)異的查找性能。

但是我們先看看,現在的散列表, 運行test3時(shí),碰撞幾率是多少。

為此,我們重構, 發(fā)生碰撞時(shí), 統計次數。

 

測試:

 

輸出:0.309

總的容量為 1024, 有1000個(gè)元素, 其中309個(gè)是發(fā)生碰撞。事故挺嚴重的。

下面我們重構HashTable類(lèi), 讓其每次達到容量的 0.75(裝載因子) 就擴充容量:)

 

首先, 我們的初始化容量為 16個(gè)(1 << 4), 然后 load factor 為0.75

 

然后在put 前檢查一下, 如有必要 resize

寫(xiě)個(gè)測試:

這個(gè)時(shí)候,同樣是添加到1000個(gè), loadFactor 此時(shí)為 0.08

我們的散列表初始大小為16,  添加到1000個(gè),要進(jìn)行若干次 resize, resize開(kāi)銷(xiāo)比較大。

我們可以重構代碼, 構造函數中指定容量大小,以避免不必要的resize開(kāi)銷(xiāo)。

但這里不做了,因為現在只是為了說(shuō)明算法, 但是使用 java.util.HashMap時(shí),就曉得了。

解決碰撞還有開(kāi)放尋址法

也是灰常容易滴, 我們添加兩個(gè)方法, put2, 和 get2, 實(shí)現看看。

使用最簡(jiǎn)單的 線(xiàn)性探查

 

同樣,寫(xiě)一個(gè)測試:

線(xiàn)性探查比較容易實(shí)現, 但是容易造成“堆在一起”的問(wèn)題, 書(shū)中稱(chēng)為:一次群集

可以采用二次探查, 或雙重散列,更好地避免這種現象

//----------

下面看看java.util.HashMap的實(shí)現,更好地了解散列表。

先看 put:

代碼中 hash 和 indexFor addEntry 是我們關(guān)心的地方。

此外: HashMap 允許使用值為 null 的key

有一個(gè) if 語(yǔ)句:

先看看 hash值是否相等, 再判斷equals

這也給出了我們重寫(xiě)equals和 hash的原則: 如果你重寫(xiě)了equals, 那么你一定要重寫(xiě) hashCode, 如果兩個(gè)對象equals,那么hashCode也一定要相等, 否則在HashMap等容器中將不能正確工作。參看《Effective Java》

再來(lái)看看 hash 和 indexFor  (中文注釋是我加的)

 

hash 根據 原h(huán)ashCode產(chǎn)生更好的散列值, 因為table的容量大小剛好為2的整數冪, 所以必須這樣做,否則hash code的高位將浪費(取模時(shí)) --- 見(jiàn)上面 除法散列

indexFor: 等于 h % length,

所以,HashMap 采用 改進(jìn)的除法散列

再看看 addEntry

table 也成倍擴展的

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Java中hashmap和hashtable的區別- 經(jīng)典
HashMap的實(shí)現原理和底層數據結構
JVM里面hashtable和hashmap實(shí)現原理
HashMap和Hashtable 之原代碼詳解 (轉載)
js實(shí)現 hashMap
JDK源碼分析(10)之 Hashtable 相關(guān)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久