博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一,撸基础篇系列,JAVA的那些数据结构应用
阅读量:5885 次
发布时间:2019-06-19

本文共 6222 字,大约阅读时间需要 20 分钟。

hot3.png

181324_Q3Od_867417.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.51void 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

 

094041_qOI9_867417.png

 

 

 

 

转载于:https://my.oschina.net/u/867417/blog/844987

你可能感兴趣的文章
Android网络编程11之源码解析Retrofit
查看>>
韩国SK电讯宣布成功研发量子中继器
查看>>
TCP - WAIT状态及其对繁忙的服务器的影响
查看>>
安全预警:全球13.5亿的ARRIS有线调制解调器可被远程攻击
查看>>
麦子学院与阿里云战略合作 在线教育领军者技术实力被认可
查看>>
正确看待大数据
查看>>
Facebook通过10亿单词构建有效的神经网络语言模型
查看>>
发展大数据不能抛弃“小数据”
查看>>
中了WannaCry病毒的电脑几乎都是Win 7
查看>>
学生机房虚拟化(九)系统操作设计思路
查看>>
nginx报错pread() returned only 0 bytes instead of 4091的分析
查看>>
质数因子
查看>>
Spring源码浅析之事务(四)
查看>>
[转载] Live Writer 配置写 CSDN、BlogBus、cnBlogs、163、sina 博客
查看>>
SQL:连表查询
查看>>
MySQL日期函数、时间函数总结(MySQL 5.X)
查看>>
c语言用尾插法新建链表和输出建好的链表
查看>>
高性能 Oracle JDBC 编程
查看>>
java 中ResultSet可以获取的数据类型及返回值类型列表
查看>>
ubuntu 13 安装SH程序
查看>>