圖解Java中的資料結構及原理,傻瓜也能看懂!

java填坑路發表於2018-12-05

最近在整理資料結構方面的知識, 系統化看了下Java中常用資料結構, 突發奇想用動畫來繪製資料流轉過程。

主要基於jdk8, 可能會有些特性與jdk7之前不相同, 例如LinkedList LinkedHashMap中的雙向列表不再是迴環的。

HashMap中的單連結串列是尾插, 而不是頭插入等等, 後文不再贅敘這些差異, 本文目錄結構如下:

LinkedList

經典的雙連結串列結構, 適用於亂序插入, 刪除. 指定序列操作則效能不如ArrayList, 這也是其資料結構決定的.

add(E) / addLast(E)

add(index, E)

這邊有個小的優化, 他會先判斷index是靠近隊頭還是隊尾, 來確定從哪個方向遍歷鏈入.

 

 

靠隊尾

get(index)

也是會先判斷index, 不過效能依然不好, 這也是為什麼不推薦用for(int i = 0; i < lengh; i++)的方式遍歷linkedlist, 而是使用iterator的方式遍歷.

remove(E)

ArrayList

底層就是一個陣列, 因此按序查詢快, 亂序插入, 刪除因為涉及到後面元素移位所以效能慢.

add(index, E)

擴容

一般預設容量是10, 擴容後, 會length*1.5.

remove(E)

迴圈遍歷陣列, 判斷E是否equals當前元素, 刪除效能不如LinkedList.

Stack

經典的資料結構, 底層也是陣列, 繼承自Vector, 先進後出FILO, 預設new Stack()容量為10, 超出自動擴容.

push(E)

pop()

字尾表示式

Stack的一個典型應用就是計算表示式如 9 + (3 – 1) * 3 + 10 / 2, 計算機將中綴表示式轉為字尾表示式, 再對字尾表示式進行計算。

中綴轉字尾

數字直接輸出

棧為空時,遇到運算子,直接入棧

遇到左括號, 將其入棧

遇到右括號, 執行出棧操作,並將出棧的元素輸出,直到彈出棧的是左括號,左括號不輸出。

遇到運算子(加減乘除):彈出所有優先順序大於或者等於該運算子的棧頂元素,然後將該運算子入棧

最終將棧中的元素依次出棧,輸出。

計算字尾表達

遇到數字時,將數字壓入堆疊

遇到運算子時,彈出棧頂的兩個數,用運算子對它們做相應的計算, 並將結果入棧

重複上述過程直到表示式最右端

運算得出的值即為表示式的結果

佇列

與Stack的區別在於, Stack的刪除與新增都在隊尾進行, 而Queue刪除在隊頭, 新增在隊尾.

ArrayBlockingQueue

生產消費者中常用的阻塞有界佇列, FIFO.

put(E)

put(E) 佇列滿了

 

 

take()

當元素被取出後, 並沒有對陣列後面的元素位移, 而是更新takeIndex來指向下一個元素.

takeIndex是一個環形的增長, 當移動到佇列尾部時, 會指向0, 再次迴圈.

 

HashMap

最常用的雜湊表, 面試的童鞋必備知識了, 內部通過陣列 + 單連結串列的方式實現. jdk8中引入了紅黑樹對長度 > 8的連結串列進行優化, 我們另外篇幅再講。推薦閱讀:Java 程式設計師必須掌握的 8 道資料結構面試題,你會幾道?

put(K, V)

put(K, V) 相同hash值

resize 動態擴容

當map中元素超出設定的閾值後, 會進行resize (length * 2)操作, 擴容過程中對元素一通操作, 並放置到新的位置。

具體操作如下:

在jdk7中對所有元素直接rehash, 並放到新的位置.

在jdk8中判斷元素原hash值新增的bit位是0還是1, 0則索引不變, 1則索引變成”原索引 + oldTable.length”.

 

 

LinkedHashMap

繼承自HashMap, 底層額外維護了一個雙向連結串列來維持資料有序. 可以通過設定accessOrder來實現FIFO(插入有序)或者LRU(訪問有序)快取.

put(K, V)

get(K)

accessOrder為false的時候, 直接返回元素就行了, 不需要調整位置. 

accessOrder為true的時候, 需要將最近訪問的元素, 放置到隊尾.

removeEldestEntry 刪除最老的元素

歡迎工作一到五年的Java工程師朋友們加入Java填坑之路:860113481
群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用”沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!
 


相關文章