JAVA的那些数据结构实现总结,实现,扩容说明
能沉淀下來的東西,往往都很基礎,整理了下JAVA中遇到的數據結構
目錄大綱:
到目前接觸到的
有幾個說明:
可擴容數組
ArrayList 擴容數組的實現, 滿了后擴容,擴容在1.5倍,通過copy過來,無擴容因子
int newCapacity = oldCapacity + (oldCapacity >> 1);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
可擴容的數組鏈表
數組鏈表的擴容實現:
以HashMap為例子, 當鏈表深度過長,或生產個新的數組鏈表進行copy
注意:
擴容過程中容易出現死鏈,下面是死鏈的個演示:
擴容前
[ 1 ] [ 2 ] [ 3 ] [ 空]
5 10
第一個線程擴容后,數組鏈表如下
[ 1 ] [ 10 ] [3] [] [] [] []
2
第二個線程又把從頭把2指向10,然后2和10形成了個死循環
擴容代碼
//對HashMap死鏈理解的注解 . 2017.02.17 by 何錦彬 JDK,1.7.51
void transfer(Entry[] newTable, boolean rehash) {
//獲取新table的容量
int newCapacity = newTable.length;
//迭代以前的數組
for (Entry<K,V> e : table) {
//如果數組上有元素
while(null != e) {
// 賦值next
Entry<K,V> next = e.next;
//獲取e在新的table里的位置
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
//把e指向當前的新數組里的第一個元素,這里會并發了,如果在這斷點等待下個線程過來,就會死循環,嘗試下
e.next = newTable[i];
//替代新數組的位置
newTable[i] = e;
e = next;
}
}
}
棧
stack棧的實現 ,基于數組繼承自Vector(故線程安全):
獲取peek():get(len-1)
出棧 pop(): 從數組最大坐標開始取出,peek(len-1) , 然后remove
入棧 push(o) : add(o)
阻塞隊列
阻塞隊列的實現:
基于數組和單向鏈表
獲取:peek(),
實現:重入鎖保證線程安全,peek(),從頂部獲取
阻塞入隊:put(o),
實現: 重入鎖保證線程安全,通過Condition阻塞,無超時,支持Interrupt
帶超時阻塞入隊: offer(o,timeout, tmeUnit),
實現: 重入鎖保證線程安全,通過Condition阻塞,condition方法,awaitNanos(納秒),支持Interrupt
其它注意點:
當前數組的大小: AtomicInteger計算,用CAS保證同步,記得ReentrantLock必須是全局變量,局部的話,每次鎖的對象是this.
紅黑樹:
紅黑樹的實現,TreeMap舉例,加入自己的注釋的理解:
//對treeMap的紅黑樹理解注解. 2017.02.16 by 何錦彬 JDK,1.7.51<br> <br>/** From CLR */
private void fixAfterInsertion(Entry<K, V> x) { //新加入紅黑樹的默認節點就是紅色
x.color = RED;
/**
* 1. 如為根節點直接跳出
*/
while (x != null && x != root && x.parent.color == RED) { if (parentOf(x) == leftOf(parentOf(parentOf(x)))) { //如果X的父節點(P)是其父節點的父節點(G)的左節點
//即 下面這種情況
/**
* G
* P(RED) U
*/
//獲取其叔(U)節點
Entry<K, V> y = rightOf(parentOf(parentOf(x)));
if (colorOf(y) == RED) {
// 這種情況,對應下面 圖:情況一
/**
* G
* P(RED) U(RED)
* X
*/
//如果叔節點是紅色的(父節點有判斷是紅色). 即是雙紅色,比較好辦,通過改變顏色就行. 把P和U都設置成黑色然后,X加到P節點。 G節點當作新加入節點繼續迭代
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
} else {
//處理紅父,黑叔的情況
if (x == rightOf(parentOf(x))) {
// 這種情況,對應下面 圖:情況二
/**
* G
* P(RED) U(BLACK)
* X
*/
//如果X是右邊節點
x = parentOf(x);
// 進行左旋
rotateLeft(x);
}
//左旋后,是這種情況了,對應下面 圖:情況三
/**
* G
* P(RED) U(BLACK)
* X
*/ // 到這,X只能是左節點了,而且P是紅色,U是黑色的情況
//把P改成黑色,G改成紅色,以G為節點進行右旋
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateRight(parentOf(parentOf(x)));
}
} else {
//父節點在右邊的
/**
* G
* U P(RED)
*/
//獲取U
Entry<K, V> y = leftOf(parentOf(parentOf(x))); if (colorOf(y) == RED) {
//紅父紅叔的情況
/**
* G
* U(RED) P(RED)
*/
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
//把G當作新插入的節點繼續進行迭代
x = parentOf(parentOf(x));
} else {
//紅父黑叔,并且是右父的情況
/**
* G
* U(RED) P(RED)
*/
if (x == leftOf(parentOf(x))) {
//如果插入的X是左節點
/**
* G
* U(BLACK) P(RED)
* X
*/
x = parentOf(x);
//以P為節點進行右旋
rotateRight(x);
}
//右旋后
/**
* G
* U(BLACK) P(RED)
* X
*/
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
//以G為節點進行左旋
rotateLeft(parentOf(parentOf(x)));
}
}
}
//紅黑樹的根節點始終是黑色
root.color = BLACK;
}
其實就是一顆2-3-4樹變種,紅黑樹詳情可以看我上一篇
而且JDK8的hashMap鏈表后,鏈表的深度超過8也是轉換成紅黑樹的存儲,個人是認為轉換成紅黑樹后,hashMap的擴容條件是有問題了,應該加入是否有紅黑樹的判斷
總結
以上是生活随笔為你收集整理的JAVA的那些数据结构实现总结,实现,扩容说明的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GStreamer开发笔记(四):ubu
- 下一篇: 2.1k star! 抓紧冲,DeepC