我是菜鸟:深入java容器二

今天晚上准备看下HashMap里面,当桶中元素达到阀值转为树型结构中的一些函数。
下面是TreeNode节点的定义:

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;  //节点颜色
        TreeNode(int hash, K key, V val, Node<K,V> next) {
            super(hash, key, val, next);
        }

由上可以看出来这里采用的红黑树作为基本的数据结构,而红黑树的讲解这里不做详述,可参见其他文章。(当时看红黑树的操作,也是看了很久才弄明白,关键是要一气呵成,不能怕,这样就能够看懂了。)
下面我们先看当一个桶中元素超过阀值的时候,将该桶的元素变为树形结构的代码:

    final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            TreeNode<K,V> hd = null, tl = null;
            // 首先将该桶中的元素中的节点转为树形节点,仍然用一个引用pre将所有的节点链接起来,形成一个以head为头结点,tail为尾节点的串。
            do {  
                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)  // 将这个树形节点的链表转为树结构 treeify(tab)
                hd.treeify(tab);
        }
    }

下面是将一个树形节点的链表转为红黑树的过程。
Forms tree of the nodes linked from this node.

 final void treeify(Node<K,V>[] tab) {
            TreeNode<K,V> root = null;
            for (TreeNode<K,V> x = this, next; x != null; x = next) {
                next = (TreeNode<K,V>)x.next;
                x.left = x.right = null;
                if (root == null) {  // 若根节点为null.
                    x.parent = null;
                    x.red = false;
                    root = x;
                }
                else {        // 如果根节点不为空,则插入当前元素,红黑树节点的插入
                    K k = x.key;
                    int h = x.hash;
                    Class<?> kc = null;
                    for (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; 
                            // 根据我们定义的比较器
                        else if ((kc == null &&
                                  (kc = comparableClassFor(k)) == null) ||
                                 (dir = compareComparables(kc, k, pk)) == 0)
                            dir = tieBreakOrder(k, pk);

                       // 插入到叶子节点
                        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、付费专栏及课程。

余额充值