【Java 基础】-- 深入剖析 Java HashMap 中的红黑树

深入剖析 Java HashMap 中的红黑树

在 Java 8 之前,HashMap 采用数组加链表的方式来处理哈希冲突。然而,当链表长度过长时,查找效率会显著下降。为了解决这一问题,Java 8 对 HashMap 进行了优化:当链表长度超过阈值(默认为 8)且数组长度大于等于 64 时,链表会转换为红黑树,以提高查找、插入和删除的效率。

红黑树概述

红黑树是一种自平衡的二叉查找树,具有以下特性:

  1. 节点颜色:每个节点要么是红色,要么是黑色。
  2. 根节点:根节点是黑色。
  3. 叶子节点:每个叶子节点(NIL)是黑色。
  4. 红色节点限制:每个红色节点的两个子节点一定都是黑色。
  5. 黑色节点平衡:从任一节点到其每个叶子节点的路径都包含数量相同的黑色节点。

这些特性确保了红黑树的平衡性,使其在最坏情况下的查找、插入和删除操作的时间复杂度维持在 O(log n)。

HashMap 中红黑树的引入

在 Java 8 中,HashMap 的底层结构在发生哈希冲突时,首先将冲突的元素以链表形式存储。当链表长度超过阈值(TREEIFY_THRESHOLD,默认为 8)且数组长度大于等于 64 时,链表会转换为红黑树,以提高操作效率。相应地,当红黑树的节点数量减少到一定程度(UNTREEIFY_THRESHOLD,默认为 6)时,红黑树会退化为链表结构。

需要注意的是,在进行树化操作时,HashMap 会先检查数组的长度是否小于 64。如果小于,则优先进行扩容而不是树化。这是因为在较小的数组中,冲突的概率更高,通过扩容可以有效减少冲突的发生,从而避免不必要的树化操作。

红黑树的优缺点

优点:

  • 自平衡性:红黑树通过严格的平衡条件,确保了树的高度不会过高,从而保证了查找、插入和删除操作的时间复杂度为 O(log n)。

  • 性能稳定:在最坏情况下,红黑树的操作效率仍然保持在对数级别,避免了普通二叉查找树在极端情况下退化为链表的情况。

缺点:

  • 实现复杂:红黑树的插入和删除操作需要通过旋转和重新着色来维护平衡,这使得其实现相对复杂。

  • 空间开销:相比于链表,红黑树的每个节点需要存储额外的颜色信息和指向父节点的引用,这增加了空间开销。

示例:链表转换为红黑树

以下是一个简单的示例,演示当 HashMap 中某个桶的链表长度超过阈值时,如何转换为红黑树:

import java.util.HashMap;
import java.util.Map;

public class HashMapTreeifyExample {
    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();

        // 插入元素,确保它们的哈希值相同,导致哈希冲突
        for (int i = 0; i < 12; i++) {
            map.put(i * 16, "Value" + i);
        }

        // 输出 HashMap 的内容
        map.forEach((key, value) -> System.out.println(key + ": " + value));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oo寻梦in记

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值