Collection <類型>
List 可以重複,有順序
ArrayList 主選
結構:數組 特點:查找快,增刪慢 線程不安全,效率高
Vector
結構:數組 特點:查找快,增刪慢 線程安全,效率低
Stack
結構:棧 特點:Vector的子類,也定義了自己的一些方法。 線程安全,效率低
LinkedList
結構:鏈表 特點:查找慢,增刪快 線程不安全,效率低
Set 唯一性,沒有順序
HashSet
結構:哈希表 通過hashCode()、equals()保證元素的唯一性 元素的排列是無序的 線程不安全
基於 HashMap 實現的,HashSet 底層使用 HashMap 來保存所有元素
LinkedHashSet
結構:鏈表+哈希表 與HashSet相比,由鏈表保證元素有序 線程不安全
TreeSet
結構:紅黑樹 排序方法有自然排序、比較器排序 唯一性通過存放值時比較返回值是否爲0,0既有相同值 線程不安全
TreeSet實現了對TreeMap的封裝
實現了Serializable接口,因此它支持序列化,實現了Cloneable接口,能被克隆
Hash值衝突
hash值衝突是發生在put()時,hash值是通過hash(key.hashCode())來獲取的,當put的元素越來越多時,出現不同的key產生相同的hash值問題,也即是hash衝突。
分離鏈表法
對於相同的哈希值,使用鏈表進行連接。使用數組存儲每一個鏈表。
put的時候地址上存在value,則再對比key是否相同,若hash值和key都相同,則替換value,若hash值相同,key不相同,則形成一個單鏈表,將hash值相同,key不同的元素以Entry<V,V>的方式存放在鏈表中,這樣就解決了hash衝突。
開放地址方法
按順序決定哈希值時,如果某數據的哈希值已經存在,則在原來哈希值的基礎上往後加一個單位,直至不發生哈希衝突。
Map<key,value>
HashMap 主選
結構:哈希表(數組+鏈表) 無序的 只允許一個key爲null,可多個值爲null 線程不安全
採用分離鏈表法解決衝突
通過hashCode()、equals()保證元素的唯一性,hashCode()確定數組位置,equlas()確定鏈表位置。
實現了Serializable接口,因此它支持序列化,實現了Cloneable接口,能被克隆。
JDK1.8增加了紅黑樹來進行優化。即當鏈表超過8時,鏈表就轉換爲紅黑樹,利用紅黑樹快速增刪改查的特點提高HashMap的性能。
LinkedHashMap
結構:數組+雙鏈表
與HashMap相比,LinkedHashMap 的元素是有序的
HashTable
結構:哈希表 不允許null做爲key 線程安全
實現了Serializable接口,它支持序列化,實現了Cloneable接口,能被克隆
TreeMap
結構:紅黑樹 排序方法有自然排序、比較器排序 線程不安全 可以插入null鍵,null值;
無序集合(插入和遍歷順序不一致)
同步容器
在Java中,同步容器主要包括2類:
- Vector、Stack、HashTable
- Collections類中提供的靜態工廠方法創建的類
缺點:
- 同步容器效率低
- 對同步容器進行迭代的同時修改它的內容,會報ConcurrentModificationException異常。
阻塞隊列:當隊列滿時,隊列會阻塞插入元素的線程,直到隊列不滿;當隊列爲空時,隊列會阻塞獲取元素的線程,直到隊列不空。
非阻塞隊列:若線程從中獲取元素,若沒有則直接返回空,不會阻塞當前線程
分段鎖:簡單來說就是將數據進行分段,每一段鎖用於鎖容器中的一部分數據,那麼當多線程訪問容器裏的不容數據段的數據時,線程間就不會存在鎖競爭,從而可以有效地提高併發訪問效率。有些方法需要跨段,比如size(),就需要按照順序鎖定所有的段,完成操作後,再按順序釋放鎖。
併發容器
非阻塞隊列
CopyOnWriteArrayList
讀寫分離,讀操作不加鎖,所有線程都不會阻塞。寫操作加鎖,線程會阻塞。
寫線程獲取到鎖,其他線程包括讀線程阻塞
實現方式是寫時複製出一個新的數組,完成插入、修改或者移除操作後將新數組賦值給array。
適用於讀遠遠大於寫的時候。
ConcurrentHashMap
多線程環境下,使用Hashmap進行put操作可能會引起死循環
採用分段鎖,有些方法需要跨段,比如size()和containsValue(),它們可能需要鎖定整個表而而不僅僅是某個段,這需要按順序鎖定所有段,操作完畢後,又按順序釋放所有段的鎖。這裏“按順序”是很重要的,否則極有可能出現死鎖。
ConcurrentLinkedQueue
一個基於鏈接節點的無界線程安全隊列。
此隊列按照 FIFO(先進先出)原則對元素進行排序,新的元素插入到隊列的尾部,隊列獲取操作從隊列頭部獲得元素。
它的主要api是offer和poll, offer將指定元素插入此隊列的尾部 ;poll 獲取並移除此隊列的頭,如果此隊列爲空,則返回 null。
阻塞隊列BlockingQueue
ArrayBlockingQueue
基於數組的阻塞隊列實現,在ArrayBlockingQueue內部,維護了一個定長數組,以便緩存隊列中的數據對象,這是一個常用的阻塞隊列,除了一個定長數組外,ArrayBlockingQueue內部還保存着兩個整形變量,分別標識着隊列的頭部和尾部在數組中的位置。
LinkedBlockingQueue
基於鏈表的阻塞隊列,同ArrayListBlockingQueue類似,其內部也維持着一個數據緩衝隊列(該隊列由一個鏈表構成),當生產者往隊列中放入一個數據時,隊列會從生產者手中獲取數據,並緩存在隊列內部,而生產者立即返回;只有當隊列緩衝區達到最大值緩存容量時(LinkedBlockingQueue可以通過構造函數指定該值),纔會阻塞生產者隊列,直到消費者從隊列中消費掉一份數據,生產者線程會被喚醒,反之對於消費者這端的處理也基於同樣的原理。
沒有指定其容量大小,LinkedBlockingQueue會默認一個類似無限大小的容量(Integer.MAX_VALUE)
PriorityBlockingQueue
支持優先級的無界阻塞隊列,默認情況下元素按照自然順序升序排列,可以自定義類實現compareTo()方法來指定元素的排序規則,或在初始化PriorityBlockingQueue時指定構造參數Comparator來對元素進行排序,但不能保證同優先級元素的順序;
樹:
滿二叉樹:除了葉節點外每一個結點都有左右子女且葉節點都處在最底層的二叉樹。
完全二叉樹:只有最下面的兩層結點度小於2,並且最下面一層的結點都集中在該層最左邊的若干位置的二叉樹。
二叉樹:查找最好O(logN),最差O(N),最差情況是所有的數據全部在一端時。
二叉查找樹:查找最好O(logN),最差O(N),最差情況是所有的數據全部在一端時
1.若任意結點的左子樹不空,則左子樹上所有結點的值均不大於它的根結點的值。
2. 若任意結點的右子樹不空,則右子樹上所有結點的值均不小於它的根結點的值。
3.任意結點的左、右子樹也分別爲二叉搜索樹。
平衡二叉樹:又稱爲AVL樹,查找O(logN),它是一顆空樹或它的左右兩個子樹的高度差的絕對值不超過1
哈夫曼樹:帶權路徑長度達到最小的二叉樹,也叫做最優二叉樹。
k層的二叉樹,最多有節點個數爲 2^k-1,最少有k個節點
第k層,最多有節點個數爲 2^(k-1)個
紅黑樹:查找刪除插入時間複雜度O(logN)
紅黑樹是每個節點都帶有顏色屬性的二叉查找樹,顏色爲紅色或黑色。在二叉查找樹強制的一般要求以外,對於任何有效的紅黑樹我們增加了如下的額外要求:
- 節點是紅色或黑色。
- 根是黑色。
- 所有葉子都是黑色(葉子是NIL節點)。
- 每個紅色節點必須有兩個黑色的子節點。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點。)
- 從任一節點到其每個葉子的所有簡單路徑都包含相同數目的黑色節點。