動圖解析:《JAVA中的數據結構及原理》

編程比如是一輛汽車,而數據結構和算法是汽車內部的變速箱。一個開車的人不懂變速箱的原理也是能開車的,同理一個不懂數據結構和算法的人也能編程。可是若是一個開車的人懂變速箱的原理,好比下降速度來得到更大的牽引力,或者經過下降牽引力來得到更快的行駛速度。最近在整理數據結構方面的知識, 系統化看了下Java中經常使用數據結構, 突發奇想用動態圖來繪製數據流轉過程。本篇文章主要基於jdk8, 可能會有些特性與jdk7之間不相同,jdk8與jdk7不一樣之處請看下圖:java


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的鏈表進行優化, 咱們另外篇幅再講。

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數據結構及原理的所有內容,但願你們對你們有所幫助,

相關文章
相關標籤/搜索