Map集合、散列表、紅黑樹介紹


前言

聲明,本文用得是jdk1.8

前面已經講了Collection的總覽和剖析List集合:

原本我是打算繼續將Collection下的Set集合的,結果看了源碼發現:Set集合實際上就是HashMap來構建的

所以,就先介紹Map集合、散列表和紅黑樹吧

看這篇文章之前最好是有點數據結構的基礎:

當然了,如果講得有錯的地方還請大家多多包涵並不吝在評論去指正~

一、Map介紹

1.1為什么需要Map

前面我們學習的Collection叫做集合,它可以快速查找現有的元素。

而Map在《Core Java》中稱之為-->映射..

映射的模型圖是這樣的:

那為什么我們需要這種數據存儲結構呢???舉個例子

  • 作為學生來說,我們是根據學號來區分不同的學生。只要我們知道學號,就可以獲取對應的學生信息。這就是Map映射的作用!

生活中還有很多這樣的例子:只要你掏出身份證(key),那就可以證明是你自己(value)

1.2Map與Collection的區別

1.3Map的功能

下面我們來看看Map的源碼:

簡單常用的Map功能有這么一些:

下面用紅色框框圈住的就是Map值得關注的子類:

二、散列表介紹

無論是Set還是Map,我們會發現都會有對應的-->HashSet,HashMap

首先我們也先得回顧一下數據和鏈表

  • 鏈表和數組都可以按照人們的意願來排列元素的次序,他們可以說是有序的(存儲的順序和取出的順序是一致的)
  • 但同時,這會帶來缺點:想要獲取某個元素,就要訪問所有的元素,直到找到為止。
  • 這會讓我們消耗很多的時間在里邊,遍歷訪問元素~

而還有另外的一些存儲結構:不在意元素的順序,能夠快速的查找元素的數據

  • 其中就有一種非常常見的:散列表

2.1散列表工作原理

散列表為每個對象計算出一個整數,稱為散列碼根據這些計算出來的整數(散列碼)保存在對應的位置上

在Java中,散列表用的是鏈表數組實現的,每個列表稱之為桶。【之前也寫過桶排序就這么簡單,可以回顧回顧】

一個桶上可能會遇到被占用的情況(hashCode散列碼相同,就存儲在同一個位置上),這種情況是無法避免的,這種現象稱之為:散列沖突

  • 此時需要用該對象與桶上的對象進行比較,看看該對象是否存在桶子上了~如果存在,就不添加了,如果不存在則添加到桶子上
  • 當然了,如果hashcode函數設計得足夠好,桶的數目也足夠,這種比較是很少的~
  • JDK1.8中,桶滿時會從鏈表變成平衡二叉樹

如果散列表太滿,是需要對散列表再散列,創建一個桶數更多的散列表,並將原有的元素插入到新表中,丟棄原來的表~

  • 裝填因子(load factor)決定了何時對散列表再散列~
  • 裝填因子默認為0.75,如果表中超過了75%的位置已經填入了元素,那么這個表就會用雙倍的桶數自動進行再散列

當然了, 在后面閱讀源碼的時候會繼續說明的,現在簡單了解一下即可~

擴展閱讀:

三、紅黑樹介紹

上面散列表中已經提過了:如果桶數滿的時候,JDK8是將鏈表轉成紅黑樹的~。並且,我們的TreeSet、TreeMap底層都是紅黑樹來實現的。

所以,在這里學習一波紅黑樹到底是啥玩意。

之前涉及過二叉樹的文章:

在未學習之前,我們可能是聽過紅黑樹這么一個數據結構類型的,還有其他什么B/B+樹等等,反正是比較復雜的數據結構了~~~

各種常見的樹的用途:

來源:
https://www.zhihu.com/question/30527705/answer/52527887

3.1回顧二叉查找樹

首先我們來回顧一下:利用二叉查找樹的特性,我們一般來說可以很快地查找出對應的元素。

可是二叉查找樹也有個例(最壞)的情況(線性):

上面符合二叉樹的特性,但是它是線性的,完全沒樹的用處~

樹是要“均衡”才能將它的優點展示出來的~,比如下面這種:

因此,就有了平衡樹這么一個概念~紅黑樹就是一種平衡樹,它可以保證二叉樹基本符合矮矮胖胖(均衡)的結構

3.2知新2-3樹

講到了平衡樹就不得不說最基礎的2-3樹,2-3樹長的是這個樣子:

在二叉查找樹上,我們插入節點的過程是這樣的:小於節點值往右繼續與左子節點比,大於則繼續與右子節點比,直到某節點左或右子節點為空,把值插入進去。這樣無法避免偏向問題

而2-3樹不一樣:它插入的時候可以保持樹的平衡

在2-3樹插入的時可以簡單總結為兩個操作:

  • 合並2-節點為3-節點,擴充將3-節點擴充為一個4-節點
  • 分解4-節點為3-節點,節點3-節點為2-節點
  • ........至使得樹平衡~

合並分解的操作還是比較復雜的,要分好幾種情況,代碼量很大這里我就不介紹了,因為要學起來是一大堆的,很麻煩

3.3從2-3樹到紅黑樹

由於2-3樹為了保持平衡性,在維護的時候是需要大量的節點交換的!這些變換在實際代碼中是很復雜的,大佬們在2-3樹的理論基礎上發明了紅黑樹(2-3-4樹也是同樣的道理,只是2-3樹是最簡單的一種情況,所以我就不說2-3-4樹了)。

  • 紅黑樹是對2-3查找樹的改進,它能用一種統一的方式完成所有變換

紅黑樹是一種平衡二叉樹,因此它沒有3-節點。那紅黑樹是怎么將3-節點來改進成全都是二叉樹呢?

紅黑樹就字面上的意思,有紅色的節點,有黑色的節點

我們可以將紅色節點的左鏈接畫平看看:

一顆典型的二叉樹:

將紅色節點的左鏈接畫平之后:得到2-3平衡樹:

3.4紅黑樹基礎知識

前面已經說了,紅黑樹是在2-3的基礎上實現的一種樹,它能夠用統一的方式完成所有變換。很好理解:紅黑樹也是平衡樹的一種,在插入元素的時候它也得保持樹的平衡,那紅黑樹是以什么的方式來保持樹的平衡的呢?

紅黑樹用的是也是兩種方式來替代2-3樹不斷的節點交換操作:

  • 旋轉:順時針旋轉和逆時針旋轉
  • 反色:交換紅黑的顏色
  • 這個兩個實現比2-3樹交換的節點(合並,分解)要方便一些

紅黑樹為了保持平衡,還有制定一些約束,遵守這些約束的才能叫做紅黑樹:

  1. 紅黑樹是二叉搜索樹。
  2. 根節點是黑色
  3. 每個葉子節點都是黑色的空節點(NIL節點)
  4. 每個紅色節點的兩個子節點都是黑色。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)
  5. 從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點(每一條樹鏈上的黑色節點數量(稱之為“黑高”)必須相等)

3.5紅黑樹總結

紅黑樹可以說是十分復雜的,我在學習的時候並沒有去認真細看當中的處理細節,只是大概的過了一遍,知道了整體~

有了前輩很多優質的資料,相信要等到想要理解其中的細節,花點力氣和時間還是可以掌握一二的。

紅黑樹參考資料:

四、總結

這篇主要介紹了Map集合的基礎知識,了解Map的常用子類~

簡單介紹了散列表和紅黑樹,他倆作為Hashxxx和Treexxx的底層,了解其整體思想和相關基礎在后續看源碼也不至於那么懵~

后續會去看Map常用子類的源碼,文章敬請期待~~~~

如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y。為了大家方便,剛新建了一下qq群:742919422,大家也可以去交流交流。謝謝支持了!希望能多介紹給其他有需要的朋友

參考資料:

  • 《Core Java》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM