圖解 Java 常用數據結構

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。

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

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

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

?

LinkedList

經典的雙鏈表結構, 適用于亂序插入, 刪除. 指定序列操作則性能不如ArrayList, 這也是其數據結構決定的.

add(E) / addLast(E)

add(index, E)

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

復制代碼

 1         if (index < (size >> 1)) {2             Node<E> x = first;3             for (int i = 0; i < index; i++)4                 x = x.next;5             return x;6         } else {7             Node<E> x = last;8             for (int i = size - 1; i > index; i--)9                 x = x.prev;
10             return x;
11         }

復制代碼

靠隊尾

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) 隊列滿了

復制代碼

1         final ReentrantLock lock = this.lock;
2         lock.lockInterruptibly();
3         try {
4             while (count == items.length)
5                 notFull.await();
6             enqueue(e);
7         } finally {
8             lock.unlock();
9         }

復制代碼

take()

當元素被取出后, 并沒有對數組后面的元素位移, 而是更新takeIndex來指向下一個元素.

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

復制代碼

 1     private E dequeue() {2         // assert lock.getHoldCount() == 1;3         // assert items[takeIndex] != null;4         final Object[] items = this.items;5         @SuppressWarnings("unchecked")6         E x = (E) items[takeIndex];7         items[takeIndex] = null;8         if (++takeIndex == items.length)9             takeIndex = 0;
10         count--;
11         if (itrs != null)
12             itrs.elementDequeued();
13         notFull.signal();
14         return x;
15     }

復制代碼

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".

復制代碼

 1     //定義兩條鏈2     //原來的hash值新增的bit為0的鏈,頭部和尾部3     Node<K,V> loHead = null, loTail = null;4     //原來的hash值新增的bit為1的鏈,頭部和尾部5     Node<K,V> hiHead = null, hiTail = null;6     Node<K,V> next;7     //循環遍歷出鏈條鏈8     do {9         next = e.next;
10         if ((e.hash & oldCap) == 0) {
11             if (loTail == null)
12                 loHead = e;
13             else
14                 loTail.next = e;
15             loTail = e;
16         }
17         else {
18             if (hiTail == null)
19                 hiHead = e;
20             else
21                 hiTail.next = e;
22             hiTail = e;
23         }
24     } while ((e = next) != null);
25     //擴容前后位置不變的鏈
26     if (loTail != null) {
27         loTail.next = null;
28         newTab[j] = loHead;
29     }
30     //擴容后位置加上原數組長度的鏈
31     if (hiTail != null) {
32         hiTail.next = null;
33         newTab[j + oldCap] = hiHead;
34     }

復制代碼

LinkedHashMap

繼承自HashMap, 底層額外維護了一個雙向鏈表來維持數據有序. 可以通過設置accessOrder來實現FIFO(插入有序)或者LRU(訪問有序)緩存.

put(K, V)

get(K)

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

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

removeEldestEntry 刪除最老的元素

?

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

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

相關文章

程序員生存定律--使人生永動的勢能

程序員生存定律這系列的目錄在這里&#xff1a;程序員生存定律--目錄 喜歡從頭瞄的&#xff0c;可以移步。 ------------------------------------------------------------------------------- 這篇說的是精神&#xff0c;比較務虛&#xff0c;不感興趣的可以略過。 在國內有…

int 和 Integer 的區別

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1、Integer是int的包裝類&#xff0c;int則是java的一種基本數據類型 2、Integer變量必須實例化后才能使用&#xff0c;而int變量不需要…

度量術語之二:應用類和開發類生產率(實際度量案例)

一個令人震驚的事實是連生產率這種常見度量數據都沒有一個簡單的定義。連我們日常經常用到的公式&#xff1a;生產率工作產品/工作量&#xff08;工作產品可以是代碼行&#xff0c;功能點&#xff0c;也可以是任何可以計數的東西&#xff0c;比如文檔頁數&#xff09;都是錯誤的…

注解 @ModelAttribute 運用詳細介紹

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。1.ModelAttribute注釋方法   例子&#xff08;1&#xff09;&#xff0c;&#xff08;2&#xff09;&#xff0c;&#xff08;3&#x…

編程語言 IDE 對比

IDE是集成開發環境的英文縮寫&#xff0c;所謂集成開發環境&#xff0c;就是將你在開發過程中所需要的工具或功能集成到了一起&#xff0c;比如代碼編寫、分析、編譯、調試等功能&#xff0c;從而最大化地提高開發者的工作效率。每種編程語言都有一些特定的IDE&#xff0c;本文…

強制更新 maven 緩存

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 mvn dependency:purge-local-repository

程序員為什么那么難升職

一個有趣的現象是老程序員很難升職&#xff0c;如果你因為3K工資太低而要辭掉工作&#xff0c;你的上司寧可去外面找一個5K工資的新人&#xff0c;也不會來挽留你。那么程序員為什么那么難升職&#xff0c;這里總結了幾點。你上司的問題你晉升困難&#xff0c;最大的主觀原因在…

Docker 安裝 Redis (Redis 配置)

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 獲取 redis 鏡像 docker pull redis 不加版本號默認獲取最新版本&#xff0c;也可以使用 docker search redis 查看鏡像來源 查看本地鏡像…

百度首席科學家 Andrew Ng談深度學習的挑戰和未來

摘要&#xff1a;7月7日上午&#xff0c;百度首席科學家Andrew Ng應邀做客中國科學院自動化研究所并做了《Deep Learning&#xff1a;Overview and trends》的學術報告。 【編者按】人工智能被認為是下一個互聯網大事件&#xff0c;當下&#xff0c;谷歌、微軟、百度等知名的高…

Linux 安裝 jdk ( 兩種方式 )

安裝jdk有兩種方法&#xff1a;手動安裝 yum安裝。 方式一&#xff1a; yum安裝 1、查詢要安裝jdk的版本, 命令&#xff1a;yum -y list java* 2、安裝jdk1.8 yum install -y java-1.8.0-openjdk.x86_64 3、查詢jdk版本&#xff1a;java -version 這樣就安裝成功了。默認…

在動態網絡下實現分布式共享存儲

摘要&#xff1a;本文介紹了分布式環境下實現共享內存模型會遇到的各種問題和挑戰&#xff0c;并針對不同問題介紹多種算法的優劣性。本文是對現階段該領域研究現狀的總體介紹&#xff0c;通過本文能了解動態分布式共享內存研究的前沿狀況、挑戰與機遇。 共享內存系統是普通單…

集合拷貝通用方法、list<A> 轉換成 list<B> (屬性相同)

拷貝2個擁有相同屬性的集合實現&#xff1a; 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 package com.hydbest.app.lbd.marketing.common.utils;import com.alibaba.fastjson.JSON…

Linkedln技術高管Jay Kreps:Lambda架構剖析

摘要&#xff1a;Jay Kreps是Linkedln的一名在線數據架構技術高管&#xff0c;在日常工作中&#xff0c;Jay Kreps經常被問及有關Lambda架構的問題&#xff0c;為此他結合實際經驗和個人體會&#xff0c;針對Lambda架構進行深度剖析&#xff0c;分析了它的優缺點以及采用的替代…

JWT ( JSON Web Token ) 入門教程

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 一、跨域認證的問題 互聯網服務離不開用戶認證。一般流程是下面這樣。 1、用戶向服務器發送用戶名和密碼。 2、服務器驗證通過后&#x…

優秀程序員必備的15大技能

編程是個很復雜的玩意&#xff0c;但是成就優秀程序員的很多因素和我們在學校中早期學到的相差無幾。本文靈感來源于Robert Fulghum的《All I Really Need to Know I Learned in Kindergarten》。 1.分享 盡可能地使用開源&#xff0c;并且如果有能力的話也可以把自己的成果分…

注解 @Target 用法

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 Target&#xff1a; Target說明了Annotation所修飾的對象范圍&#xff1a;Annotation可被用于 packages、types&#xff08;類、接口、枚…

軟件開發者如何準備未來?

摘要&#xff1a;現今&#xff0c;科技領域技術更新非常迅速&#xff0c;作為該領域幕后勤懇勞作的軟件開發者要想在其中永遠保持領先&#xff0c;跟得上時代&#xff0c;就需要時刻面向未來做好準備。但面對各種技術各種開發語言&#xff0c;軟件開發者該如何做&#xff1f; …

java 并發包之 LongAdder 源碼分析

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 LongAdder是java8中新增的原子類&#xff0c;在多線程環境中&#xff0c;它比AtomicLong性能要高出不少&#xff0c;特別是寫多的場景。…

JAVA 內存模型 (Java Memory Model,JMM)

JAVA內存模型 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 Java內存模型&#xff08;Java Memory Model&#xff0c;JMM&#xff09; 是在硬件內存模型基礎上更高層的抽象&#xf…

解決:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 報錯如下&#xff1a; java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.…