jdk1.8的HashMap中的红黑树插入,为什么是红黑树而不是AVL树

jdk1.8HashMap的源码
树节点

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);
        }

        /**
         * Returns root of tree containing this node.
         */
        final TreeNode<K,V> root() {
            for (TreeNode<K,V> r = this, p;;) {
                if ((p = r.parent) == null)
                    return r;
                r = p;
            }
        }
}

	/*
	*	入参root,根节点,x当前要插入的节点
	*
	*/
static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
                                                    TreeNode<K,V> x) {
            x.red = true;
            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
                if ((xp = x.parent) == null) {
                    x.red = false;
                    return x;
                }
                else if (!xp.red || (xpp = xp.parent) == null)
                    return root;
                if (xp == (xppl = xpp.left)) {
                    if ((xppr = xpp.right) != null && xppr.red) {
                        xppr.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                        if (x == xp.right) {
                            root = rotateLeft(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateRight(root, xpp);
                            }
                        }
                    }
                }
                else {
                    if (xppl != null && xppl.red) {
                        xppl.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                        if (x == xp.left) {
                            root = rotateRight(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateLeft(root, xpp);
                            }
                        }
                    }
                }
            }
        }

在Jdk1.8版本后,Java对HashMap做了改进,在链表长度大于8的时候,将后面的数据存在红黑树中,以加快检索速度。

那么很多人就有疑问为什么是使用红黑树而不是AVL树,AVL树是完全平衡二叉树阿?

最主要的一点是:

在CurrentHashMap中是加锁了的,实际上是读写锁,如果写冲突就会等待,如果插入时间过长必然等待时间更长,而红黑树相对AVL树他的插入更快!

第一个问题为什么不一直使用树?

我想这是内存占用与存储桶内查找复杂性之间的权衡。请记住,大多数哈希函数将产生非常少的冲突,因此为大小为3或4的桶维护树将是非常昂贵的,没有充分的理由。

作为参考,这是一个HashMap的Java 8 impl(它实际上有一个很好的解释,整个事情如何工作,以及为什么他们选择8和6,作为“TREEIFY”和“UNTREEIFY”阈值)

第二个问题为什么hash冲突使用红黑树而不是AVL树呢

在这里插入图片描述

红黑树和AVL树之间的区别

  • AVL树比红黑树保持更加严格的平衡。AVL树中从根到最深叶的路径最多为~1.44 lg(n + 2),而在红黑树中最多为~2 lg(n + 1)。
    因此,在AVL树中查找通常更快,但这是以更多旋转操作导致更慢的插入和删除为代价的。因此,如果您希望查找次数主导树的更新次数,请使用AVL树。

  • AVL以及RedBlack树是高度平衡的树数据结构。它们非常相似,真正的区别在于在任何添加/删除操作时完成的旋转操作次数。
    两种实现都缩放为a O(lg N),其中N是叶子的数量,但实际上AVL树在查找密集型任务上更快:利用更好的平衡,树遍历平均更短。另一方面,插入和删除方面,AVL树速度较慢:需要更高的旋转次数才能在修改时正确地重新平衡数据结构。

  • 对于通用实现(即先验并不清楚查找是否是操作的主要部分),RedBlack树是首选:它们更容易实现,并且在常见情况下更快 - 无论数据结构如何经常被搜索修改。一个例子,TreeMap而TreeSet在Java中使用一个支持RedBlack树。

对于小数据:

  • insert:RB tree&avl tree具有恒定的最大旋转次数,但RB树会更快,因为平均RB树使用较少的旋转。

  • 查找:AVL树更快,因为AVL树的深度较小。

  • 删除:RB树具有恒定的最大旋转次数,但AVL树可以将O(log N)次旋转视为最差。并且平均而言,RB树也具有较少的旋转次数,因此RB树更快。

对于大数据:

  • insert:AVL树更快。因为您需要在插入之前查找特定节点。当您有更多数据时,查找特定节点的时间差异与O(log N)成比例增长。但在最坏的情况下,AVL树和RB树仍然只需要恒定的旋转次数。因此,瓶颈将成为您查找该特定节点的时间。

  • 查找:AVL树更快。(与小数据情况相同)

  • 删除:AVL树平均速度更快,但在最坏的情况下,RB树更快。因为您还需要在删除之前查找非常深的节点以进行交换(类似于插入的原因)。平均而言,两棵树都有恒定的旋转次数。但RB树有一个恒定的旋转上限。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值