国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

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

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

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

《算法導(dǎo)論》第三部分 數(shù)據(jù)結(jié)構(gòu) 略過(guò) 隊(duì)列 鏈表,我們到了 散列表

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

本章真是糾結(jié),因?yàn)榭吹枚囊郧岸伎催^(guò),不懂的現(xiàn)在還是看不懂。 還好看不懂的部分都是加星號(hào)的。

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

 

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

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

 

上面的代碼當(dāng)然是通不過(guò)測(cè)試的(PS: 請(qǐng)先忘記java.util.HashTable)

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

差不多像這樣:

 

運(yùn)行測(cè)試,數(shù)組越界, 因?yàn)槲覀冞€未實(shí)現(xiàn) hash 這個(gè)方法。

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

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

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

 

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

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

現(xiàn)在運(yùn)行測(cè)試,是通過(guò)滴:)

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

Java代碼

  

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

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

重構(gòu)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ē)?yán)?,怎么辦?");   
  7.     }   
  8. }  

 

重構(gòu)get

 

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

再看乘法散列

 

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

Knuth認(rèn)為 黃金分割數(shù) 是比較理想的值((根號(hào)5 - 1) / 2 ~ 0.618), 股民朋友們一定認(rèn)識(shí)

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

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

因?yàn)檫@樣可以使用移位代替乘法計(jì)算。

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

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

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

重購(gòu)代碼試試看:

首先,數(shù)組空間大小為 2 ^ p

然后:

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

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

運(yùn)行測(cè)試,失敗, 可以看到控制臺(tái)只輸出到 108

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

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

先來(lái) 鏈接法

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

 

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

然后重構(gòu)put

 

可以看到,測(cè)試正常運(yùn)行:)

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

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

為此,我們重構(gòu), 發(fā)生碰撞時(shí), 統(tǒng)計(jì)次數(shù)。

 

測(cè)試:

 

輸出:0.309

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

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

 

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

 

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

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

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

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

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

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

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

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

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

 

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

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

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

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

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

先看 put:

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

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

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

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

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

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

 

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

indexFor: 等于 h % length,

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

再看看 addEntry

table 也成倍擴(kuò)展的

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

聯(lián)系客服