5、JDK1.8HashMap源码分析系列文章(treeifyBin,treeify)

1、TreeNode的静态方法是否对数据结构进行树化-treeify()

这里有几个参数必须区别开来

        /**
         * 桶的链表还原阈值:即 红黑树转为链表的阈值,当在扩容(resize())时(此时HashMap的数据存储位置会重新计算),
         * 在重新计算存储位置后,当原有的红黑树内数量 < 6时,则将 红黑树转换成链表
         */
        private static final int UNTREEIFY_THRESHOLD = 6;
        /**
         * 桶的树化阈值:即 链表转成红黑树的阈值,在存储数据时,当链表长度 > 该值时,则将链表转换成红黑树
         */
        private static final int TREEIFY_THRESHOLD = 8;
    /**
     * 我们可以将存放元素的数组 transient Node<K,V>[] table 理解为一个装与萨努的桶数组
     * MIN_TREEIFY_CAPACITY 默认值64(至少4倍桶的树化阈值TREEIFY_THRESHOLD,避免调整大小与树化阈值之间发生冲突),对于这个值可以理解为:当桶的数量小于这个值的时候,没有必要去进行结构转换,
     * 我们先对桶进行扩容,然后对每个桶的元素进行分散化。详见扩容方法resize().
     * 当一个数组位置上集中了多个键值对,那是因为这些key的hash值和数组长度取模之后结果相同。(并不是因为这些key的hash值相同)
     * 因为hash值相同的概率不高,所以可以通过扩容的方式,来使得最终这些key的hash值在和新的数组长度取模之后,拆分到多个数组位置上。
     */
    private static final int MIN_TREEIFY_CAPACITY = 64;
    /**
     * @param tab  存放Map的数组元素
     * @param hash 链表key的hash值
     * @return void
     * @Author muyi
     * @Date 10:25 2020/8/3
     */
    final void treeifyBin(HashMap.Node<K, V>[] tab, int hash) {
        int n, index;
        HashMap.Node<K, V> e;
        // 当桶的数组为空或者桶的数量小于64时,是不允许树化的,先对桶进行扩容,扩容完成了,如果链表的长度还是大于等于8,那么必须树化,
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            // 扩容方法,详见分析文章4
            resize();
            // 将当前节点指向链表位置的头节点元素
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            // hd-链表头节点,tl-链表尾节点,遍历链表,将链表中的所有节点替换成树形节点
            HashMap.TreeNode<K, V> hd = null, tl = null;
            do {
                // 根据链表节点生成树形节点,
                HashMap.TreeNode<K, V> p = replacementTreeNode(e, null);
                // 如果尾节点为空,当前新增节点应放在头节点位置
                if (tl == null)
                    hd = p;
                else {
                    // 如果尾节点不为空,当前节点的前驱节点指向尾节点,尾节点的后继节点指向当前节点
                    p.prev = tl;
                    tl.next = p;
                }
                // 修改尾节点的指针指向当前节点
                tl = p;
            } while ((e = e.next) != null);
            // 如果头节点不为空,对当前位置的链表进行树化
            if ((tab[index] = hd) != null)
                hd.treeify(tab);
        }
    }

2、树化方法treeifyBin(),它是HashMap的一个final方法。

        /**
         * 将双向链表进行树化
         *
         * @param tab 双向链表
         * @return void
         * @Author muyi
         * @Date 14:09 2020/7/30
         */
        final void treeify(HashMap.Node<K, V>[] tab) {
            // 存放数据的红黑树根节点,
            HashMap.TreeNode<K, V> root = null;
            // 遍历链表元素,this-当前节点(这是树形节点类的静态方法,this指的就是当前节点),next-下一个节点
            for (HashMap.TreeNode<K, V> x = this, next; x != null; x = next) {
                next = (HashMap.TreeNode<K, V>) x.next;
                x.left = x.right = null;
                // 如果root节点为空,说明当前添加的元素位于root位置,
                if (root == null) {
                    x.parent = null;
                    x.red = false;
                    root = x;
                } else {
                    K k = x.key;
                    int h = x.hash;
                    Class<?> kc = null;
                    // 比较点的hash值
                    for (HashMap.TreeNode<K, V> p = root; ; ) {
                        int dir, ph;
                        K pk = p.key;
                        if ((ph = p.hash) > h)
                            dir = -1;
                        else if (ph < h)
                            dir = 1;
                        /**
                         * 如果两个hash值相等,两个条件取或值(如果继承了comparable接口就是,没继承的话就使用默认方法进行计算)
                         * 1、(kc == null && (kc = comparableClassFor(k)) == null):实现comparable接口的类为NULL
                         * 2、(dir = compareComparables(kc, k, pk)) == 0:
                         */
                        else if ((kc == null && (kc = comparableClassFor(k)) == null) ||
                                (dir = compareComparables(kc, k, pk)) == 0)
                            dir = tieBreakOrder(k, pk);
                        HashMap.TreeNode<K, V> xp = p;
                        // 如果当前节点的hash值较小,则置于左子树,反之,则置于右子树
                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
                            x.parent = xp;
                            if (dir <= 0)
                                xp.left = x;
                            else
                                xp.right = x;
                            // 平衡红黑树
                            root = balanceInsertion(root, x);
                            break;
                        }
                    }
                }
            }
            // 将根节点移动到链表的头节点
            moveRootToFront(tab, root);
        }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值