java 树 数据结构 xml_一,撸基础篇系列,JAVA的那些数据结构应用

b6a1fb04aecaaf8ff11157769d6a2abe.png

到目前接触到的

有几个说明:

可扩容数组

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);

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.

非阻塞并发队列

单向 ConcurrentLinkedQueue

ConcurrentLinkedQueue的size有个小坑, 为了offer时的速度,并没有存储个当前队列的大小。 故调用concurrentLinkedQueue.size()时就坑了,只能去遍历整个列

数组链表

数组链表的扩容实现:

以HashMap为例子:

扩容过程:

扩容前

[ 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 e : table) {

//如果数组上有元素

while(null != e) {

// 赋值next

Entry 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;

}

}

}

红黑树:

红黑树的实现,TreeMap举例,:

//对treeMap的红黑树理解注解. 2017.02.16 by 何锦彬 JDK,1.7.51
/** From CLR */

private void fixAfterInsertion(Entry 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 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 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树变种

环链表+SET,如redis的HashedWheelTimer

d7c93f355a1166392614f7eb3fd71274.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值