为什么 `HashMap` 在 Java 8 之后选择使用红黑树,而不是普通的平衡二叉树?

为什么 HashMap 在 Java 8 之后选择使用红黑树,而不是普通的平衡二叉树?

在 Java 8 之前,HashMap 采用 数组 + 链表 解决哈希冲突,查询时间复杂度最坏情况下可达 O(n)。Java 8 引入 红黑树(Red-Black Tree) 作为优化方案,使得查询时间复杂度降低至 O(log n)

那么,为什么 HashMap 选择 红黑树 而不是 AVL 树(严格平衡二叉搜索树) 这样的普通平衡二叉树呢?本文从 平衡性、性能、插入删除复杂度 角度进行解析。


1. 红黑树 vs. 普通平衡二叉树

特性 红黑树(Red-Black Tree) AVL 树(严格平衡二叉搜索树)
平衡性 近似平衡(允许局部不平衡) 严格平衡(每个节点的左右子树高度差 ≤ 1)
查找时间复杂度 O(log n)(比链表快) O(log n)(比红黑树更平衡)
插入删除复杂度 O(log n)(少量旋转) O(log n)(旋转次数更多)
旋转操作 最多 2 次旋转(调整成本低) 最多 log(n) 次旋转(调整成本高)
性能 插入/删除操作更快 查找稍快,但插入删除开销大

结论

  • AVL 树查找比红黑树更快(更严格平衡),但插入/删除代价更高。
  • 红黑树允许适度不平衡,减少插入/删除时的旋转成本,性能更优。

2. HashMap 选择红黑树的核心原因

(1)插入和删除性能更优

HashMap 中,当 链表长度 ≥ 8 时,转换为红黑树,提高查找效率。

  • 如果使用 AVL 树

    • AVL 树是严格平衡的,每次插入/删除都需要调整,使左右子树高度相等。
    • 可能需要 多次旋转(最坏 log(n) 次),导致 插入/删除成本较高
  • 如果使用红黑树

    • 允许局部不平衡,每次插入/删除只需 最多 2 次旋转(而不是 log(n) 次)。
    • 插入和删除更快,适合 HashMap 的高并发环境

结论HashMap 需要高效的插入和删除,因此红黑树更优。


(2)查询速度的折中

  • AVL 树比红黑树查找更快(树更平衡,查询路径更短)。
  • 但在 HashMap 中,树的高度最多是 log(8) = 3(最多 8 个节点)。
    • 由于树的规模很小,AVL 树的查找优势并不明显
    • 但如果使用 AVL 树,插入/删除成本会变高。

结论HashMap 中红黑树的 O(log 8) ≈ O(3) ≈ O(1) 查找速度已经足够快,没必要用 AVL 树提高查询速度,而应该优化插入/删除。


(3)减少 CPU 计算开销

  • AVL 树 为了保证平衡,需要在每次插入/删除后执行 严格的平衡检测
  • 红黑树 允许局部不平衡,减少了 不必要的旋转操作,减少 CPU 计算量,提高整体性能。

结论:红黑树比 AVL 树 计算成本更低,插入/删除操作更快


3. HashMap 中的红黑树转换规则

Java 8 HashMap 规定:

  • 当桶中的链表 长度 ≥ 8,转换为 红黑树(提高查找速度)。
  • 当桶中的元素 减少到 ≤ 6,转换回 链表(减少额外的内存开销)。
  • 这两个阈值的设计是经验优化,避免频繁转换导致的性能损耗。

4. 总结

HashMap 选择红黑树的原因

  1. 插入/删除性能更优:红黑树 最多 2 次旋转,而 AVL 树需要 log(n) 次旋转,插入/删除更快。
  2. 查询速度折中HashMap 的红黑树高度 最多 log(8) ≈ 3,查询速度已经接近 O(1),无需 AVL 树的极致平衡。
  3. 减少 CPU 计算成本:红黑树的平衡调整更少,减少额外计算,提高整体性能。
  4. 适合 HashMap 的动态存储:当链表 ≥ 8 时转换为树,≤ 6 时恢复为链表,节省内存。

为什么不用 AVL 树?

  • AVL 树插入/删除旋转次数多,调整成本太高
  • HashMap 中的树 不会太深,AVL 树的查询优化 意义不大

5. 代码示例

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

public class HashMapTreeExample {
    public static void main(String[] args) {
        // 创建 HashMap
        Map<Integer, String> map = new HashMap<>();
        
        // 插入 8 个哈希冲突的 Key,触发红黑树转换
        for (int i = 0; i < 8; i++) {
            map.put(i * 16, "Value" + i); // 产生相同 hash 桶
        }
        
        System.out.println("HashMap size: " + map.size());
    }
}

当同一哈希桶中元素 ≥ 8,转换为红黑树,提高查询效率。


6. 结论

HashMap 选择红黑树而不是 AVL 树,主要是因为:

  • 插入/删除更快(红黑树的旋转次数更少)。
  • 查询速度已经足够快(最多 log(8) = 3 层)。
  • 计算开销更低(红黑树的平衡调整更少)。
  • 节省内存(数据少时转换回链表)。

🚀 因此,Java 8 HashMap 选择红黑树,避免了 AVL 树的高维护成本,提高了性能!

posted on   滚动的蛋  阅读(21)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
历史上的今天:
2024-02-27 关于Hash Table
2024-02-27 事物隔离级别
2020-02-27 SpringBoot 一个依赖搞定 session 共享,没有比这更简单的方案了
2020-02-27 Java 将文件打包为zip压缩包下载

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示