• 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的扩容条件是有问题了,应该加入是否有红黑树的判断

  • 相关阅读:
    Picture
    wolf and rabbit
    十进制转换为二进制(一直不会算的)
    各种排序
    折线分割平面
    字母数
    1001
    Primes
    大数的减法神秘数
    转: Windows Internet WinINet 学习笔记(2)
  • 原文地址:https://www.cnblogs.com/springsource/p/6437657.html
Copyright © 2020-2023  润新知