深入了解HashMap


什么是hash?
哈希算法將任意長度的二進制值映射為較短的固定長度的二進制值,這個小的二進制值稱為哈希值。哈希值是一段數據唯一且極其緊湊的數值表示形式。如果散列一段明文而且哪怕只更改該段落的一個字母,隨后的哈希都將產生不同的值。要找到散列為同一個值的兩個不同的輸入,在計算上是不可能的,所以數據的哈希值可以檢驗數據的完整性。一般用于快速查找和加密算法。

1、任意長度的二進制值
2、映射關系(哈希算法,數學的一些列算法)
3、固定的二進制值(哈希值)

任意長度的二進制值 和 固定長度的二進制值 是一一對應關系
固定長度的二進制值就相當于一個任意長度的二進制值的一個摘要
固定長度的二進制值 相當于一個關鍵字key

為什么這樣做?
舉個例子,比如這里有一萬首歌,給你一首新的歌X,要求你確認這首歌是否在那一萬首歌之內。無疑,將一萬首歌一個一個比對非常慢。但如果存在一種方式,能將一萬首歌的每首數據濃縮到一個數字(稱為哈希碼)中,于是得到一萬個數字,那么用同樣的算法計算新的歌X的編碼,看看歌X的編碼是否在之前那一萬個數字中,就能知道歌X是否在那一萬首歌中。

hash表特點:
1、存取效率很高。取數據的時間復雜度為1。
hash表與其他數組如順序表,鏈表不同。
順序表,使用數組實現,一組地址連續的存儲單元,數組大小有兩種方式指定,一是靜態分配,二是動態擴展。
查找的時候,如果知道值的下標,那么查找時間復雜度為1。但多數場景是不知道值的下標的,只能for循環一個個比較,直到找到值位置。因此大多數場景下取值的時間復雜度為n。

鏈表的定義是遞歸的,它或者為空null,或者指向另一個節點node的引用,這個節點含有下一個節點或鏈表的引用。
與順序存儲相比,允許存儲空間不連續,插入刪除時不需要移動大量的元素,只需修改指針即可,但查找某個元素,只能從頭遍歷整個鏈表。查找時間復雜度為n。

hash表
傳入一個key,把key代入哈希函數里,通過計算就能得到一個哈希值,而該哈希值就是value的下標,由此找到value值,查找時間復雜度為1。

---以下是轉載內容---

原文地址:http://www.iteye.com/topic/539465

?

Hashmap是一種非常常用的、應用廣泛的數據類型,最近研究到相關的內容,就正好復習一下。網上關于hashmap的文章很多,但到底是自己學習的總結,就發出來跟大家一起分享,一起討論。?


1、hashmap的數據結構?
要知道hashmap是什么,首先要搞清楚它的數據結構,在java編程語言中,最基本的結構就是兩種,一個是數組,另外一個是模擬指針(引用),所有的數據結構都可以用這兩個基本結構來構造的,hashmap也不例外。Hashmap實際上是一個數組和鏈表的結合體(在數據結構中,一般稱之為“鏈表散列“),請看下圖(橫排表示數組,縱排表示數組元素【實際上是一個鏈表】)。
?



從圖中我們可以看到一個hashmap就是一個數組結構,當新建一個hashmap的時候,就會初始化一個數組。我們來看看java代碼:?

Java代碼??收藏代碼
  1. /**?
  2. ?????*?The?table,?resized?as?necessary.?Length?MUST?Always?be?a?power?of?two.?
  3. ?????*??FIXME?這里需要注意這句話,至于原因后面會講到?
  4. ?????*/??
  5. ????transient?Entry[]?table;??

Java代碼??收藏代碼
  1. static?class?Entry<K,V>?implements?Map.Entry<K,V>?{??
  2. ????????final?K?key;??
  3. ????????V?value;??
  4. ????????final?int?hash;??
  5. ????????Entry<K,V>?next;??
  6. ..........??
  7. }??


??????? 上面的Entry就是數組中的元素,它持有一個指向下一個元素的引用,這就構成了鏈表。?
???????
? 當我們往hashmap中put元素的時候,先根據key的hash值得到這個元素在數組中的位置(即下標),然后就可以把這個元素放到對應的位置中了。如果這個元素所在的位子上已經存放有其他元素了,那么在同一個位子上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。從hashmap中get元素時,首先計算key的hashcode,找到數組中對應位置的某一元素,然后通過key的equals方法在對應位置的鏈表中找到需要的元素。從這里我們可以想象得到,如果每個位置上的鏈表只有一個元素,那么hashmap的get效率將是最高的,但是理想總是美好的,現實總是有困難需要我們去克服,哈哈~?

2、hash算法?
我們可以看到在hashmap中要找到某個元素,需要根據key的hash值來求得對應數組中的位置。如何計算這個位置就是hash算法。前面說過hashmap的數據結構是數組和鏈表的結合,所以我們當然希望這個hashmap里面的元素位置盡量的分布均勻些,盡量使得每個位置上的元素數量只有一個,那么當我們用hash算法求得這個位置的時候,馬上就可以知道對應位置的元素就是我們要的,而不用再去遍歷鏈表。?

所以我們首先想到的就是把hashcode對數組長度取模運算,這樣一來,元素的分布相對來說是比較均勻的。但是,“模”運算的消耗還是比較大的,能不能找一種更快速,消耗更小的方式那?java中時這樣做的,
?

Java代碼??收藏代碼
  1. static?int?indexFor(int?h,?int?length)?{??
  2. ???????return?h?&?(length-1);??
  3. ???}??


首先算得key得hashcode值,然后跟數組的長度-1做一次“與”運算(&)。看上去很簡單,其實比較有玄機。比如數組的長度是2的4次方,那么hashcode就會和2的4次方-1做“與”運算。很多人都有這個疑問,為什么hashmap的數組初始化大小都是2的次方大小時,hashmap的效率最高,我以2的4次方舉例,來解釋一下為什么數組大小為2的冪時hashmap訪問的性能最高。?

???????? 看下圖,左邊兩組是數組長度為16(2的4次方),右邊兩組是數組長度為15。兩組的hashcode均為8和9,但是很明顯,當它們和1110“與”的時候,產生了相同的結果,也就是說它們會定位到數組中的同一個位置上去,這就產生了碰撞,8和9會被放到同一個鏈表上,那么查詢的時候就需要遍歷這個鏈表,得到8或者9,這樣就降低了查詢的效率。同時,我們也可以發現,當數組長度為15的時候,hashcode的值會與14(1110)進行“與”,那么最后一位永遠是0,而0001,0011,0101,1001,1011,0111,1101這幾個位置永遠都不能存放元素了,空間浪費相當大,更糟的是這種情況中,數組可以使用的位置比數組長度小了很多,這意味著進一步增加了碰撞的幾率,減慢了查詢的效率!
?

?


????????? 所以說,當數組長度為2的n次冪的時候,不同的key算得得index相同的幾率較小,那么數據在數組上分布就比較均勻,也就是說碰撞的幾率小,相對的,查詢的時候就不用遍歷某個位置上的鏈表,這樣查詢效率也就較高了。?
????????? 說到這里,我們再回頭看一下hashmap中默認的數組大小是多少,查看源代碼可以得知是16,為什么是16,而不是15,也不是20呢,看到上面annegu的解釋之后我們就清楚了吧,顯然是因為16是2的整數次冪的原因,在小數據量的情況下16比15和20更能減少key之間的碰撞,而加快查詢的效率。?

所以,在存儲大容量數據的時候,最好預先指定hashmap的size為2的整數次冪次方。就算不指定的話,也會以大于且最接近指定值大小的2次冪來初始化的,代碼如下(HashMap的構造方法中):
?
Java代碼??收藏代碼
  1. //?Find?a?power?of?2?>=?initialCapacity??
  2. ????????int?capacity?=?1;??
  3. ????????while?(capacity?<?initialCapacity)???
  4. ????????????capacity?<<=?1;??

3、hashmap的resize?

?????? 當hashmap中的元素越來越多的時候,碰撞的幾率也就越來越高(因為數組的長度是固定的),所以為了提高查詢的效率,就要對hashmap的數組進行擴容,數組擴容這個操作也會出現在ArrayList中,所以這是一個通用的操作,很多人對它的性能表示過懷疑,不過想想我們的“均攤”原理,就釋然了,而在hashmap數組擴容之后,最消耗性能的點就出現了:原數組中的數據必須重新計算其在新數組中的位置,并放進去,這就是resize。?

???????? 那么hashmap什么時候進行擴容呢?當hashmap中的元素個數超過數組大小*loadFactor時,就會進行數組擴容,loadFactor的默認值為0.75,也就是說,默認情況下,數組大小為16,那么當hashmap中元素個數超過16*0.75=12的時候,就把數組的大小擴展為2*16=32,即擴大一倍,然后重新計算每個元素在數組中的位置,而這是一個非常消耗性能的操作,所以如果我們已經預知hashmap中元素的個數,那么預設元素的個數能夠有效的提高hashmap的性能。比如說,我們有1000個元素new HashMap(1000), 但是理論上來講new HashMap(1024)更合適,不過上面annegu已經說過,即使是1000,hashmap也自動會將其設置為1024。 但是new HashMap(1024)還不是更合適的,因為0.75*1000 < 1000, 也就是說為了讓0.75 * size > 1000, 我們必須這樣new HashMap(2048)才最合適,既考慮了&的問題,也避免了resize的問題。?


4、key的hashcode與equals方法改寫?
在第一部分hashmap的數據結構中,annegu就寫了get方法的過程:首先計算key的hashcode,找到數組中對應位置的某一元素,然后通過key的equals方法在對應位置的鏈表中找到需要的元素。所以,hashcode與equals方法對于找到對應元素是兩個關鍵方法。?

Hashmap的key可以是任何類型的對象,例如User這種對象,為了保證兩個具有相同屬性的user的hashcode相同,我們就需要改寫hashcode方法,比方把hashcode值的計算與User對象的id關聯起來,那么只要user對象擁有相同id,那么他們的hashcode也能保持一致了,這樣就可以找到在hashmap數組中的位置了。如果這個位置上有多個元素,還需要用key的equals方法在對應位置的鏈表中找到需要的元素,所以只改寫了hashcode方法是不夠的,equals方法也是需要改寫滴~當然啦,按正常思維邏輯,equals方法一般都會根據實際的業務內容來定義,例如根據user對象的id來判斷兩個user是否相等。?
在改寫equals方法的時候,需要滿足以下三點:?
(1) 自反性:就是說a.equals(a)必須為true。?
(2) 對稱性:就是說a.equals(b)=true的話,b.equals(a)也必須為true。?
(3) 傳遞性:就是說a.equals(b)=true,并且b.equals(c)=true的話,a.equals(c)也必須為true。?
通過改寫key對象的equals和hashcode方法,我們可以將任意的業務對象作為map的key(前提是你確實有這樣的需要)。
?

總結:?
??????? 本文主要描述了HashMap的結構,和hashmap中hash函數的實現,以及該實現的特性,同時描述了hashmap中resize帶來性能消耗的根本原因,以及將普通的域模型對象作為key的基本要求。尤其是hash函數的實現,可以說是整個HashMap的精髓所在,只有真正理解了這個hash函數,才可以說對HashMap有了一定的理解。
?



本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/538225.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/538225.shtml
英文地址,請注明出處:http://en.pswp.cn/news/538225.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

snort入侵檢測系統下載Linux,入侵檢測系統Snort 2.9.0.2 發布

Snort 是一個免費的、跨平臺的軟件包&#xff0c;用作監視小型 TCP/IP 網的嗅探器、日志記錄、侵入探測器。Snort 是全世界上使用最廣泛的入侵預防與偵測軟件。Snort 有三種工作模式&#xff1a;嗅探器、數據包記錄器、網絡入侵檢測系統。嗅探器模式僅僅是從網絡上讀取數據包并…

IRC BOT原來是利用IRC下發CC命令——在xx云環境遇到了,惡意軟件開的是6666端口...

Backdoor/IRC.RpcBot 本詞條缺少名片圖&#xff0c;補充相關內容使詞條更完整&#xff0c;還能快速升級&#xff0c;趕緊來編輯吧&#xff01;Backdoor/IRC.RpcBot是一些批處理文件、腳本文件和執行文件的集合&#xff0c;也是一種黑客工具&#xff0c;這些文件的名稱是可以變化…

科大奧銳實驗報告霍爾效應_大學物理實驗報告系列之霍爾效應

【實驗名稱】霍爾效應【實驗目的】1&#xff0e;了解霍爾效應實驗原理以及有關霍爾器件對材料要求的知識。2&#xff0e;學習用“對稱測量法”消除付效應的影響&#xff0c;測量試樣的VH—IS&#xff1b;和VH—IM曲線。3&#xff0e;確定試樣的導電類型、載流子濃度以及遷移率。…

Android studio http 代理設置

Android studio http 代理設置 大連東軟信息學院鏡像服務器地址: - http://mirrors.neusoft.edu.cn 端口&#xff1a;80

三位數倒序數C語言,C語言求助!一個三位數的逆序數,總是編不對

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓#include #include #include int main(){int n,a,b,c,sum,ge,shi,bai;printf("請輸入一個三位整數&#xff1a;\n");scanf("%d",&n);nfabs(n);an/100;b(n-a*100)/10;cn%10;if(a>b&&b>c){gec…

DB2 存儲過程中執行動態SQL的兩種寫法

樣本代碼&#xff1a; DROP PROCEDURE QUOTATION.COPY_SAMPLE; CREATE PROCEDURE QUOTATION.COPY_SAMPLE (IN tableNameFrom VARCHAR(30), IN tableNameTo VARCHAR(30), INOUT copyResult INTEGER)BEGINDECLARE SQLCODE INTEGER DEFAULT 0;SET copyResult 0;-- Proecss 1BEGIN…

tp5 批量更新多條記錄_Thinkphp批量更新數據的方法匯總

以下小編給大家列出了三種實現thinkphp批量更新數據的方法,寫的不好還請見諒,有意見歡迎提出,共同學習進步! 方法一: //批量修改 data二維數組 field關鍵字段 參考ci 批量修改函數 傳參方式 function batch_update($table_name=,$data=array(),$field=){if(!$table_name||…

linux shmmax單位,Linux核心參數Shmmax,shmall,shmni

Linux 下核心參數調整kernel.shmmaxshmmax是核心參數中最重要的參數之一&#xff0c;用于定義單個共享內存段的最大值&#xff0c;shmmax設置應足夠大&#xff0c;能在一個共享內存段下容納下整個的SGA&#xff0c;設置的過低可能會導致需要創建多個共享內存段&#xff0c;可能…

制作一個App的完整流程是哪些

APP開發流程其實并不復雜&#xff0c;但是對于客戶來說&#xff0c;。一般移動APP開發都離不開UI設計師、前端開發、后端開發、測試專員、產品經理等&#xff0c;由于他們的工作性質都不一樣&#xff0c;我們且先把APP軟件開發項目分為三個階段&#xff1a;一、功能需求階段1.功…

Failed to find Build Tools revision 26.0.1

Error:A problem occurred configuring project :app. > Failed to find Build Tools revision 26.0.1 在build.gradle 中buildToolsVersion 如何修改。看本地安裝了哪些版本的 進入文件夾Android SDK 目錄下build-tools&#xff0c;修改為里面有的版本

netty 游戲服務器框圖_基于Netty和WebSocket協議實現Web端自動打印訂單服務方法與流程...

本發明涉及電子商務技術領域&#xff0c;尤其涉及一種基于netty和websocket協議實現web端自動打印訂單服務方法。背景技術&#xff1a;電子商務是以信息網絡技術為手段&#xff0c;以商品交換為中心的商務活動&#xff1b;也可理解為在互聯網(internet)、企業內部網(intranet)和…

小學數學動畫 android,小學數學動畫教學下載-小學數學動畫 安卓版v5.0-pc6手機下載...

小學數學動畫教學軟件是一款能讓孩子愛上數學的客戶端應用&#xff0c;小學數學動畫app以動畫的形式帶領孩子學習數學知識以及各類公式原理&#xff0c;測底掌握數學方法。功能介紹小學數學動畫通過形象、生動、清楚、易懂的觸摸動畫向你解釋小學數學知識和原理(小學數學原理和…

存儲芯片在智能化產業鏈中扮演的角色將更加重要

隨著大數據、云計算、物聯網等發展&#xff0c;存儲芯片作為半導體元器件中不可或缺的組成部分&#xff0c;在內存、消費電子、智能終端等領域均有著非常廣泛的應用。近年來&#xff0c;國家把集成電路產業列為“十三五”期間重要的新型戰略性產業&#xff0c;國產化“存儲芯片…

Tomcat下找不到properties文件

在java core項目里&#xff0c;目錄結構如下&#xff1a; 當使用 InputStream ipsnew FileInputStream("config/config.properties");能讀到properties文件。但是在java web項目時&#xff0c;部署到Tomcat后。上面的讀法就不行了。 javaweb項目結構如下&#xff1a…

win10計算器rsh_Win10 內置計算器評測:PowerShell 很靠譜

計算器幾乎是每個操作系統都具備的工具&#xff0c;不管是手機還是電腦&#xff0c;很多人都離不開它。然而這些系統內置計算器標準模式往往功能比較簡單&#xff0c;基本上只用于單步運算&#xff0c;就像傳統計算器那樣&#xff0c;現在的Win10計算器也是如此。不過Windows10…

android tcpdump log分析,android 系統啟動過程中加入tcpdump和logcat

一、android 系統啟動過程中加入tcpdump &#xff0c;分析開機啟動后&#xff0c;系統與服務器端的消息交互。1. init.rc 中的修改1)在init.rc 中加上tcpdump service.service tcpdump /system/xbin/tcpdump -s 0 -w/data/test/test_1.pcapclass core2)在init.rc 中啟動tcpdump…

Linux下查看軟件安裝路徑(whereis)

原文鏈接&#xff1a;http://blog.csdn.net/ly_feng/article/details/7898649----------------------------------------------------------------一、查看文件安裝路徑&#xff1a;由于初次大部分軟件的安裝都是系統自動安裝的&#xff0c;所有先說查看文件安裝的所有路徑(地址…

CloudDBA新功能上線--SQL過濾/限制/防火墻

1 前言 CloudDBA是阿里云數據庫團隊開發的智能診斷和優化平臺&#xff0c;可以幫助用戶更好使用阿里云數據庫。CloudDBA不斷提升算法和規則&#xff0c;更好的匹配更多用戶場景&#xff0c;剛剛上線了SQL過濾功能&#xff0c;用來解決某類SQL給系統帶來的沖擊。 2 功能描述 匹配…

js導出的xlsx無法打開_js文件操作之——導出Excel (js-xlsx)

前陣子跟server同學討論一個Excel導出的需求&#xff0c;我說JS搞不定&#xff0c;需要server來做&#xff0c;被server同學強行打臉。今天研究了下&#xff0c;尼瑪&#xff0c;不光可以&#xff0c;還很強大了&#xff01;總結&#xff1a;經驗是害人的&#xff0c;尤其是在發…

Linux上Svn環境搭建

一般情況下&#xff0c;Linux都是自帶SVN環境的。 查看svn是否安裝了 [14:50:28][rootVM60 ~]# rpm -aq subversion [14:50:30]subversion-1.6.11-9.el6_4.x86_64 [14:52:01][rootVM60 ~]# whereis svn [14:52:01]svn: /usr/bin/svn /usr/share/man/man1/svn.1.gz [14:55:…