zoukankan      html  css  js  c++  java
  • 对把JDK源码的一些注解,笔记

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

    /** 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 = 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, HASHMAP的死链问题

      

    //对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; } } }

      

     扩容前


    [ 1 ] [ 2 ] [ 3 ] [ 空]
      5     10

    第一个线程扩容后,数组链表如下

    [ 1 ] [ 10 ] [3] [] [] [] []
              2

    第二个线程又把从头把2指向10,然后2和10形成了个死循环

    HashMap在 JDK8后 把数组链表变成了数组+链表+红黑树. 链表为O(n),而红黑树为O(logN)

     for (int binCount = 0; ; ++binCount) {
                        if ((e = p.next) == null) {
                            p.next = newNode(hash, key, value, null);
                            //JDK8 的hashmap,链表到了8就需要变成颗红黑树了
                            if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                treeifyBin(tab, hash);
                            break;
                        }

    调整红黑树的方法其实和treeMap的一样了

    如下:

    //hashmap的红黑树平衡
             static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
                                                                TreeNode<K,V> x) {
                        x.red = true;
                        //死循环加变量定义,总感觉JAVA很少这样写代码 哈
                        for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
                            //xp X父节点, XPP X的祖父节点,  XPPL 祖父左节点  XXPR 祖父右节点  
                            if ((xp = x.parent) == null) {
                                x.red = false;
                                return x;
                            }
                            // 如果父节点是黑色, 或者XP父节点是空,直接返回
                            else if (!xp.red || (xpp = xp.parent) == null)
                                return root;
                            
                            // 下面的代码就和上面的很treeMap像了,
                           
                            if (xp == (xppl = xpp.left)) {
                                 // 第一种情况, 赋值xppl
                                //父节点是左节点的情况,下面这种
                                /**
                                 *                         G
                                 *               P(RED)              U
                                 */              
                                if ((xppr = xpp.right) != null && xppr.red) {
                                    //如果红叔的情况
                                     // 这种情况
                                    /**
                                     *                         G
                                     *               P(RED)              U(RED)
                                     *          X
                                     */
                                     //改变其颜色,
                                    xppr.red = false;
                                    xp.red = false;
                                    xpp.red = true;
                                    x = xpp;
                                }
                                else {
                                     // 黑叔的情况
                                    //  这种情况
                                  /**
                                     *                         G
                                     *               P(RED)              U(BLACK)
                                     */
                                    if (x == xp.right) {
                                        //如果插入节点在右边 这种
                                         // 这种情况
                                        /**
                                         *                           G
                                         *            P(RED)                        U(BLACK)
                                         *                     X
                                         */
                                        //需要进行左旋
                                        root = rotateLeft(root, x = xp);
                                        xpp = (xp = x.parent) == null ? null : xp.parent;
                                    }
                                    //左旋后情况都是这种了
                                    /**
                                     *                           G
                                     *            P(RED)                        U(BLACK)
                                     *      X
                                     */
                                    // 到这,X只能是左节点了,而且P是红色,U是黑色的情况
                                    if (xp != null) {
                                    //把P和G改成黑色,以G为节点进行右旋
                                        xp.red = false;
                                        if (xpp != null) {
                                            xpp.red = true;
                                            root = rotateRight(root, xpp);
                                        }
                                    }
                                }
                            }
                            else {
                                 //父节点在右边的
                                /**
                                 *                         G
                                 *                 U               P(RED)
                                 */              
                                //获取U
                                if (xppl != null && xppl.red) {
                                    //红父红叔的情况
                                     /**
                                     *                           G
                                     *                 U(RED)               P(RED)
                                     */              
                                    xppl.red = false;
                                    xp.red = false;
                                    xpp.red = true;
                                    x = xpp;
                                }
                                else {
                                 
                                    if (x == xp.left) {
                                        //如果插入的X是右节点
                                      /**
                                         *                            G
                                         *            U(BLACK)                        P(RED)
                                         *                                       X              
                                         */
                                        root = rotateRight(root, x = xp);
                                        xpp = (xp = x.parent) == null ? null : xp.parent;
                                    }
                                    //右旋后
                                    /**
                                     *                            G
                                     *            U(BLACK)                        P(RED)
                                     *                                                        X
                                     */
                                    if (xp != null) {
                                        xp.red = false;
                                        if (xpp != null) {
                                            xpp.red = true;
                                            root = rotateLeft(root, xpp);
                                        }
                                    }
                                }
                            }
                        }
  • 相关阅读:
    warning: rpmts_HdrFromFdno: Header V4 DSA/SHA1 Signature, key ID 192a7d7d: NOKEY
    warning: rpmts_HdrFromFdno: Header V3 RSA/SHA256 Signature, key ID fd431d51: NOKEY
    535 5.7.8 Error: authentication failed: generic failure安装EMOS时SMTP测试报错
    mysql-libs版本冲突卸载不了
    history
    CentOS 7 / RHEL 7 运行单用户模式进行root的密码重置
    chkconfig
    Linux主机名域名修改问题
    Mysql正常启动之后默认使用的文件
    解决mysql“Access denied for user 'root'@'localhost'”
  • 原文地址:https://www.cnblogs.com/springsource/p/6406178.html
Copyright © 2011-2022 走看看