红黑树是什么,为什么HashMap使用红黑树代替数组+链表?

前言

        我们都知道在HashMap中,当数组长度大于64并且链表长度大于8时,HashMap会从数组+链表的结构转换成红黑树,那为什么要转换成红黑树呢,或者为什么不一开始就使用红黑树呢?接下来我们将去具体的去剖析一下!

一、首先介绍一下红黑树?

        红黑树是一种自平衡的二叉搜索树,它是一种在插入和删除操作时能够自我调整以保持平衡的数据结构。红黑树之所以称为红黑树,是因为每个节点都具有颜色属性,可以是红色或黑色,这些颜色属性必须满足一定的约束条件,以确保树的平衡性。

红黑树必须满足四个条件!

  1. 根节点是黑色的。
  2. 每个叶子节点(NIL节点,即空节点)是黑色的。
  3. 如果一个节点是红色的,则它的两个子节点都是黑色的(不能有连续的红色节点)。
  4. 从任一节点到其每个叶子的所有路径都包含相同数量的黑色节点(黑色节点的数量被称为该节点的“黑色高度”)。

然后它在插入和删除具体是怎么实现的,相对来说过程会比较复杂,简单概括以下步骤:

  1. 刚插入的节点,默认是红色节点,它会一次次进行比较,比当前节点小就放在左边,比当前节点大就放在右边,也就是二分查找,所以复杂度是O(log n);
  2. 那接下来就是要满足上面的四个条件了,大概实现就是会在爷叔父节点之间进行一个红黑颜色互换,或者说在自旋之后再进行颜色互换,以满足上述四个条件。

当然,想了解红黑树插入和删除具体是怎么实现的,可以看这个视频,讲的很清晰:https://www.bilibili.com/video/BV18C4y137jn?vd_source=b16ef7f0a66010623908ff61e2645909

二、HashMap为什么使用红黑树代替数组+链表?

在说这个问题之前,先说一下数组、链表和红黑树各自的一个特点

1、数组

  • 查询快:数组支持通过索引进行 O(1) 时间复杂度的一个随机访问,这意味着可以直接访问任何位置的元素。并且数组在内存中是连续存储的,这种紧凑的布局有利于 CPU 缓存的命中率,提高访问效率;
  • 增删慢:在数组中插入元素需要将插入位置后面的所有元素向后移动一个位置,以便为新元素腾出空间,这涉及到大量元素的移动,尤其是在数组的开头或中间插入元素时。 类似地,从数组中删除元素时,需要将删除位置后面的所有元素向前移动一个位置,以填补删除元素留下的空隙。所以当对最后一个元素进行增删时,复杂度是O(1),对其它元素进行增删时,复杂度是O(n);
  • 需要预先分配内存:数组在使用前需要预先分配内存空间,其大小通常是固定的。

2、链表

  • 查询慢:链表查找元素需要从头节点开始按顺序遍历到目标位置,时间复杂度为 O(n)。并且,链表中的节点在内存中是分散存储的,这可能导致缓存不命中,从而降低访问效率。
  • 增删快:链表的插入和删除操作具有 O(1) 的时间复杂度,无论是在链表的头部、尾部还是中间插入或删除元素,都只需要修改相邻节点的指针,而不需要移动其他元素。
  • 无需预先分配内存: 链表不需要预先分配连续的内存空间,每个节点可以在需要时动态分配,这意味着链表可以轻松地扩展或收缩,不会浪费内存。

3、红黑树

  • 查询,增删都比较快:因为它是一种二分查找树,它的查询、增删的时间复杂度都为O(log n),虽然它的查询速度比不过数组,修改速度比不过链表,但是在大量的数据下,红黑树非常的稳定,它的修改效率远远大于数组,查询效率远远大于链表;
  • 有序性: 红黑树是一种有序的数据结构,可以轻松实现范围查询、有序遍历等操作。
  • 动态性能好: 红黑树能够适应动态数据的变化,保持较为稳定的性能表现。

那其实答案也是很明显了,也就是在HashMap存了大量的数据情况下,数组的查询效率可以,但是增删效率太慢了,链表的增删效率可以,但是查询效率太慢了,而红黑树刚好是个折中的选择,它的增删改查效率都很不错,都是O(log n)。

那为什么是数组长度大于64并且链表长度大于8才转换成红黑树?为什么不一开始就使用红黑树呢?

我们来看看HashMap源码注释是怎么说的:

        大概意思就是说,因为树节点所占的空间是普通节点的两倍,所以我们只有在桶中包含足够的普通节点时才使用树节点。

        而为什么阈值是8,这涉及到一个泊松分布的概念在理想情况下,桶(bins)中链表长度的值符合泊松分布,当链表长度为 8 的时候,概率仅为 0.00000006。 所以在理论上来说,当存入1666万数据的时候,链表长度才会达到8。

        从平均查找长度来看,红黑树复杂度是O(log n),它的平均查找长度是log n,如果长度为8,则log n=3;而链表的复杂度为O(n),最好的情况为1次,最坏的情况为n次,平均查找长度为n/2,长度为8时,n/2=4,所以阈值8时,红黑树的检索效率要大于链表。

        当长度为6时红黑树退化为链表,是因为log n=log 6约等于2.6,而n/2=6/2=3,两者相差不大,而红黑树节点占用的内存空间是普通节点的两倍,所以此时转换最合适。

三、总结

为什么不一开始就使用红黑树?

  1. 在数组长度和链表长度不大的时候,数组+链表的性能也很好;
  2. 而红黑树插入元素时,需要保证满足红黑树的四个特性,那它红黑颜色替换,或者自旋后替换,需要消耗一定的性能;
  3. 并且树节点所占的空间是普通节点的两倍,那它需要占用更多的内存空间。
  4. 一句话就是,小而美,迫不得已才用红黑树,杀鸡焉用牛刀!

那为什么是当数组长度大于64并且链表长度大于8时,才转换成红黑树?

  1. 在理想情况下,桶(bins)中链表长度的值符合泊松分布,当链表长度为 8 的时候,概率仅为 0.00000006。 在理论上来说,当存入1666万数据的时候,链表长度才会达到8。
  2. 而通常我们的 Map 里面是不会存储这么多的数据的,所以通常情况下,并不会发生从链表向红黑树的转换。
  3. 所以我们平时基本见不到转换成红黑树的场景,但是假如你重写hashCode()方法进行恶搞,让它每次都是固定值,那他就会发生hash碰撞,每次碰撞都会加入链表尾部,当链表长度大于8时,很可能就转换成红黑树了。这点可以注意一下,hashCode()请不要设置固定值,不然很容易树化,到时候内存占用会增加一倍!

ps:以下是我整理的java面试资料,感兴趣的可以看看。最后,创作不易,觉得写得不错的可以点点关注!

链接:https://www.yuque.com/u39298356/uu4hxh?# 《Java知识宝典》 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/784390.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java计算机网络(一)-- url,tcp,udp,socket

网络编程: 计算机网络 计算机网络指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统、网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。 网络协议…

0.5米多光谱卫星影像在农业中进行地物非粮化、非农化监测

一、引言 随着科技的发展,卫星遥感技术已经成为了农业领域中重要的数据来源。其中,多光谱卫星影像以其独特的优势,在农业应用中发挥着越来越重要的作用。本文将重点探讨0.5米加2米多光谱卫星影像在农业中的应用。 二、多光谱卫星影像概述 多…

机器学习全攻略:概念、流程、分类与行业应用案例集锦

目录 1.引言 2.从零开始认识机器学习:基本概念与重要术语 3.五步走:掌握机器学习项目执行的完整流程 3.1.问题定义与数据收集 3.2.数据预处理与特征工程 3.3.模型选择与训练 3.4.模型评估与优化 3.5.模型部署与监控 4.深入了解各类机器学习方法…

Python爬虫-懂车帝城市销量榜单

前言 本文是该专栏的第23篇,后面会持续分享python爬虫干货知识,记得关注。 最近粉丝留言咨询某汽车平台的汽车销量榜单数据,本文笔者以懂车帝平台为例,采集对应的城市汽车销量榜单数据。 具体的详细思路以及代码实现逻辑,跟着笔者直接往下看正文详细内容。(附带完整代码…

pnpm比npm、yarn好在哪里?

前言 pnpm对比npm/yarn的优点: 更快速的依赖下载更高效的利用磁盘空间更优秀的依赖管理 我们按照包管理工具的发展历史,从 npm2 开始讲起: npm2 使用早期的npm1/2安装依赖,node_modules文件会以递归的形式呈现,严格…

统计子矩阵(前缀和+双指针)

题目描述 给定一个 N M 的矩阵 A,请你统计有多少个子矩阵 (最小 1 1,最大 N M) 满足子矩阵中所有数的和不超过给定的整数 K? 输入格式 第一行包含三个整数 N, M 和 K. 之后 N 行每行包含 M 个整数,代表矩阵 A. 输出格式 一个整数…

Django DRF视图

文章目录 一、DRF类视图介绍APIViewGenericAPIView类ViewSet类ModelViewSet类重写方法 二、Request与ResponseRequestResponse 参考 一、DRF类视图介绍 在DRF框架中提供了众多的通用视图基类与扩展类,以简化视图的编写。 • View:Django默认的视图基类&…

ES的RestClient相关操作

ES的RestClient相关操作 Elasticsearch使用Java操作。 本文仅介绍CURD索引库和文档!!! Elasticsearch基础:https://blog.csdn.net/weixin_46533577/article/details/137207222 Elasticsearch Clients官网:https://ww…

(文章复现)考虑分布式电源不确定性的配电网鲁棒动态重构

参考文献: [1]徐俊俊,吴在军,周力,等.考虑分布式电源不确定性的配电网鲁棒动态重构[J].中国电机工程学报,2018,38(16):4715-47254976. 1.摘要 间歇性分布式电源并网使得配电网网络重构过程需要考虑更多的不确定因素。在利用仿射数对分布式电源出力的不确定性进行合…

博客页面---前端

目录 主页 HTML CSS 文章详细页面 HTML CSS 登录页面 HTML CSS 文章编辑页 HTML CSS 这只是前端的页面组成&#xff0c;还没有接入后端&#xff0c;并不是完全体 主页 HTML <!DOCTYPE html> <!-- <html lang"en"> --> <head>&…

区间预测 | Matlab实现带有置信区间的BP神经网络时间序列未来趋势预测

区间预测 | Matlab实现带有置信区间的BP神经网络时间序列未来趋势预测 目录 区间预测 | Matlab实现带有置信区间的BP神经网络时间序列未来趋势预测预测效果基本介绍研究回顾程序设计参考资料预测效果 基本介绍 BP神经网络(Backpropagation neural network)是一种常用的人工神…

DisplayPort 的演变

HDMI 2.0的传输带宽18Gbit/s; DP 1.2 的传输带宽17.28Gbit/s理论上HDMI 2.0高一点&#xff0c;实际上没区别.。 HDMI接口和DP接口的区别 1、厂商不同HDMI是电视机厂商主导的,而DP是由PC及芯片制造商联盟开发的.需要注意的是,HDMI需要授权费,DP则不需要. 2、版本进化。 2006 年…

http模块 设置资源类型(mime类型)

虽然浏览器自带websocket功能它会根据响应回来的内容自动去判断资源类型&#xff0c;但是我们加上了mime类型判断代码会更加规范些 一、mime类型概念&#xff1a; 媒体类型是一种标准&#xff0c;它用来表示文档。文件、字节流的性质和格式。HTTP服务可以设置响应头Content-T…

【InternLM 实战营第二期笔记】InternLM1.8B浦语大模型趣味 Demo

体验环境 平台&#xff1a;InternStudio GPU&#xff1a;10% 配置基础环境 studio-conda -o internlm-base -t demo 与 studio-conda 等效的配置方案 conda create -n demo python3.10 -y conda activate demo conda install pytorch2.0.1 torchvision0.15.2 torchaudio2…

Tidb和MySQL性能简单测试对比

一、单SQL性能对比 由于TiDB的并发能力优秀&#xff0c;但是单个SQL执行延迟较差&#xff0c;为了客观对比&#xff0c;所以只用1个线程来压测tidb和mysql&#xff0c;以观察延迟情况 二、并发SQL性能对比 TiDB:v6.5.2 MySQL:8.0.26 &#xff08;单机&#xff09; 三、结论 …

155 Linux C++ 通讯架构实战10,工具telent 和 wireshark的使用

telnet工具使用介绍 windows 上开启telnet linux 上开始telnet 使用telnet //是一款命令行方式运行的客户端TCP通讯工具&#xff0c;可以连接到服务器端&#xff0c;往服务器端发送数据&#xff0c;也可以接收从服务器端发送过来的信息&#xff1b; //类似nginx5_1_1_clie…

上位机图像处理和嵌入式模块部署(qmacvisual形状匹配)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在qmacvisual软件当中&#xff0c;提供了两种模板匹配的方法。除了前面介绍的灰度匹配&#xff0c;就是今天讲的形状匹配。当然&#xff0c;对于使…

嵌入式linux学习之opencv交叉编译

1.下载opencv源码 OpenCV官方源码下载链接为https://opencv.org/releases/&#xff0c;选择3.4.16版本下载。放在ubuntu系统~/opencv文件夹中&#xff0c;解压缩&#xff0c;opencv文件夹中新建build和install文件夹用于存放编译文件和安装文件&#xff1a; 2. 安装编译工具…

设计模式学习笔记 - 设计模式与范式 -行为型:2.观察者模式(下):实现一个异步非阻塞的EventBus框架

概述 《1.观察者模式&#xff08;上&#xff09;》我们学习了观察者模式的原理、实现、应用场景&#xff0c;重点节介绍了不同应用场景下&#xff0c;几种不同的实现方式&#xff0c;包括&#xff1a;同步阻塞、异步非阻塞、进程内、进程间的实现方式。 同步阻塞最经典的实现…

最优算法100例之18-列升序行升序的数组中查找元素

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样一…