HashMap红黑树原理解析

article/2025/11/3 15:42:28

HashMap红黑树原理解析

定义
简单来说红黑树是一种近视平衡二叉查找树,主要优点是”平衡”,即左右子树高度几乎一致,以此来防止树退化为链表,通过这种方式来保障查找的时间复杂度为log(n)。

下面先主要提一下红黑树的特性:
节点是红色或黑色。
根是黑色。
所有叶子都是黑色(叶子是NIL节点)。
每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

结构如图所示:

在这里插入图片描述
结构调整:
》当红黑树结构发生变化时,红黑树的条件可能会被破坏,需要通过自身调整方能使平衡二叉查找树变为红黑树
调整一般分为两类:
一类是改变某节点颜色(相对简单)
二类是改变树结构(通过左旋、右旋)

2.1左旋:
如下图所示:
在这里插入图片描述
重点:主要是将P的右子树通过逆时针旋转的方式旋转,成为P节点的父节点,同时将相关节点的引用进行调整,在不改变树的稳定性的前提下,可以使左子树的深度+1,右子树的深度-1,通过这种方式来保证树的平衡

源码分析:
》属性

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

》左旋

static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,TreeNode<K,V> p) {
// r: p的right节点,pp: p的parent节点,rl: p右孩子的左孩子节点 TreeNode<K,V> r, pp, rl;if (p != null && (r = p.right) != null) {// 若R为空,旋转则毫无意义if ((rl = p.right = r.left) != null)//  rl与p右节点=r的左节点(r的左节点不为空)rl.parent = p; // p的左节点则为r.leftif ((pp = r.parent = p.parent) == null)// 若p的父节点为空(root = r).red = false; .// root节点为r并设置黑色else if (pp.left == p)// 判断P节点是根节点的左孩子还是有孩子pp.left = r;elsepp.right = r;r.left = p;p.parent = r;}return root;
}

在这里插入图片描述
2.2右旋
基本逻辑是一样的,只是方向变了,p的左子树绕p顺时针旋转,成为p的parent节点,右子树深度+1,左子树深度-1
如下图所示:
在这里插入图片描述
》右旋(与左旋操作一样,只需要将左旋对应的方向换下)

static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,TreeNode<K,V> p) {TreeNode<K,V> l, pp, lr;if (p != null && (l = p.left) != null) {if ((lr = p.left = l.right) != null)lr.parent = p;if ((pp = l.parent = p.parent) == null)(root = l).red = false;else if (pp.right == p)pp.right = l;elsepp.left = l;l.right = p;p.parent = l;}return root;
}

右旋图:
在这里插入图片描述
2.3插入节点

// 插入根据hash值来判断大小
// 如果当前需要插入的类型和正在比对的节点key值是comparable,可以直接通过接口比较
final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,int h, K k, V v) {Class<?> kc = null;boolean searched = false;TreeNode<K,V> root = (parent != null) ? root() : this; // 获取根节点for (TreeNode<K,V> p = root;;) {int dir, ph; K pk;  dir:遍历的方向 -1:左孩子方向 1:右孩子方向 ph:p节点hash值if ((ph = p.hash) > h)dir = -1;else if (ph < h)dir = 1;// 因查找二叉树不允许存在相同的key,如果key存在的话则需要返回节点// 则表示插入失败(插入失败,hashmap在后续调用方那会更新值)else if ((pk = p.key) == k || (k != null && k.equals(pk)))return p;else if ((kc == null &&
// 尝试从对象k中找到一个Comparable<x.getClass()> 对象(kc = comparableClassFor(k)) == null) ||(dir = compareComparables(kc, k, pk)) == 0) {if (!searched) {TreeNode<K,V> q, ch;searched = true;
// 如果在p的左子树或者右子树找到目标元素if (((ch = p.left) != null &&(q = ch.find(h, k, kc)) != null) ||((ch = p.right) != null &&(q = ch.find(h, k, kc)) != null))return q;}
// 通过比较两个对象是否是同一类型,如果是,则调用本地方法将两个对象生成对一个的hashcode,hashcode相等的话,则返回-1,否则1dir = tieBreakOrder(k, pk);}TreeNode<K,V> xp = p;
//下面条件成立,则说明找到了目标操作元素if ((p = (dir <= 0) ? p.left : p.right) == null) {Node<K,V> xpn = xp.next;TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);// 元素节点if (dir <= 0)xp.left = x;elsexp.right = x;
//因为TreeNode今后可能退化成链表,因此需要在这里维护链表的next属性xp.next = x;x.parent = x.prev = xp;//节点插入完成if (xpn != null)((TreeNode<K,V>)xpn).prev = x;
//插入操作完成之后就要进行一定的调整操作了moveRootToFront(tab, balanceInsertion(root, x));return null;}}
}
// 获取跟节点
final TreeNode<K,V> root() {for (TreeNode<K,V> r = this, p;;) {// 若父节点为空,则说明当前节点为跟节点if ((p = r.parent) == null)return r;r = p;}
}

2.4查找节点

// 指定key查找对应的TreeNode
final TreeNode<K,V> find(int h, Object k, Class<?> kc) {TreeNode<K,V> p = this;do {int ph, dir; K pk;// 与前面插入节点参数一样TreeNode<K,V> pl = p.left, pr = p.right, q;if ((ph = p.hash) > h)// p的hash元素hashp = pl; // 取p的左子节点else if (ph < h) // 同理相反p = pr; else if ((pk = p.key) == k || (k != null && k.equals(pk)))// 如果key相等return p; // 返回当前元素else if (pl == null)p = pr; else if (pr == null)p = pl;// 如果可以根据compareTo比较则进行比较else if ((kc != null ||(kc = comparableClassFor(k)) != null) &&(dir = compareComparables(kc, k, pk)) != 0)p = (dir < 0) ? pl : pr;// 根据compareTo的结果在右孩子上继续查找else if ((q = pr.find(h, k, kc)) != null)return q;// 若compareTo结果在左孩子上,则继续查找elsep = pl;} while (p != null);return null;
}

2.5确保给定的跟节点是容器的第一个节点

static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {int n;
// 根节点不能为空,table数组不能为空if (root != null && tab != null && (n = tab.length) > 0) {// 获取根节点下标位置int index = (n - 1) & root.hash;TreeNode<K,V> first = (TreeNode<K,V>)tab[index];
// 如果当前下标位置对象与需要验证的对象不是同一个对象if (root != first) {Node<K,V> rn;// 设置红黑树根节点的值设置为头节点tab[index] = root;TreeNode<K,V> rp = root.prev;if ((rn = root.next) != null)
// 将跟节点的下一个节点的上节点指跟节点的上一节点((TreeNode<K,V>)rn).prev = rp;if (rp != null)rp.next = rn; // 将跟节点的上节点的下节点指向跟节点的下一个节点if (first != null)first.prev = root;// 将源头节点上节点指向跟节点root.next = first;// 将跟节点的下节点指向源头节点root.prev = null;// 将跟节点上节点设为null}assert checkInvariants(root);// 检查节点是否满足红黑树规则}
}

参考文章:https://blog.csdn.net/javageektech/article/details/102385013、https://www.jianshu.com/p/34b6878ae6de


http://chatgpt.dhexx.cn/article/eFfN7Esi.shtml

相关文章

红黑树的原理及实现

红黑树的原理及实现 一、什么是红黑树二、定义红黑树三、左旋和右旋四、红黑树插入节点 一、什么是红黑树 红黑树是一种特定类型的二叉树&#xff0c;它是在计算机科学中用来组织数据比如数字的块的一种结构。 红黑树是一种平衡二叉查找树的变体&#xff0c;它的左右子树高差有…

【图文详解】彻底了解红黑树底层实现原理

红黑树定义 红黑树&#xff08;Red Black Tree&#xff09; 是一种自平衡二叉查找树&#xff0c;是在计算机科学中用到的一种数据结构&#xff0c;典型的用途是实现关联数组。 红黑树是一种特化的AVL树&#xff08;平衡二叉树&#xff09;&#xff0c;都是在进行插入和删除操…

红黑树(一)之 原理和算法详细介绍

概要 目录1 红黑树的介绍2 红黑树的应用3 红黑树的时间复杂度和相关证明4 红黑树的基本操作(一) 左旋和右旋5 红黑树的基本操作(二) 添加6 红黑树的基本操作(三) 删除 作者&#xff1a;Sky Wang 于 2013-08-08 概述&#xff1a;R-B Tree&#xff…

数据结构 | 【红黑树】图解原理

今天我们要说的红黑树就是就是一棵非严格均衡的二叉树&#xff0c;均衡二叉树又是在二叉搜索树的基础上增加了自动维持平衡的性质&#xff0c;插入、搜索、删除的效率都比较高。红黑树也是实现 TreeMap 存储结构的基石。 红黑树就是非严格均衡的二叉搜索树。 一、红黑树规则特…

红黑树原理简单解析

一、红黑树为什么会出现呢&#xff1f; 是因为二叉搜索树有可能会出现极端的情况&#xff0c;就是只有一侧有数据&#xff0c;那这样的话就会降级为链表。后来出现了平衡二叉树&#xff0c;但是由于强制平衡所导致付出的代价比较高昂&#xff0c;所以黑红树出现了。 二、简介…

laravel框架的下载与安装

首先我们先访问这个网址https://github.com/laravel/laravel 可以使用git克隆 或者直接下载安装包到自己的www目录下解压&#xff0c;此时访问localhost下的laravel目录&#xff0c; 此时会报没有vendor文件夹的一个错&#xff0c; 如果你已经下载了composer 在该文件夹目录下…

Laravel

Laravel的安装 1.确认composer已经安装 2.配置homestead.yaml文件sites&#xff1a;- map: laravel.xyz//域名配置to: /home/vagrant/code/laravel/public//入口文件路径 databases&#xff1a;//数据库- laravel 3.用秘钥登录homestead 4.更换中国镜像&#xff1a; composer…

Laravel下载文件及文档

2019独角兽企业重金招聘Python工程师标准>>> Laravel学院提供的相关资源下载 中文文档 Laravel 5.6 中文文档&#xff1a;PDF&#xff08;兼容 5.5 文档&#xff09; Laravel 5.3 中文文档&#xff1a;CHM | PDF Laravel 5.2 中文文档&#xff1a;CHM | PDF Laravel…

Laravel-admin的安装步骤

1、先确保是否安装composer&#xff0c;laravel及其版本并切换到阿里镜像 composer -v 查看composer的版本 php artisan 查看laravel的版本 扩展说明下&#xff1a;如果已经安装好composer&#xff0c;也可以通过 Composer 安装 Laravel 安装器 命令如下&#xff1a;composer…

如何正确的下载安装使用别人的laravel项目?

转载的,写的很简洁明了,白俊瑶博客 laravel 作为最流行的 php 框架&#xff1b;自然少不了很多基于 laravel 开发的项目&#xff1b;不过很多项目因为还处于开发中&#xff1b;或者其他原因并没有写安装文档&#xff1b;举个反面栗子&#xff1b;比如说我的 laravel-bjyadmin ;…

laravel 5.0

1.应用场景 使用PHP5.4[因为php5.4只能最高支持laravel 5.0]快速开发/维护一个web系统 2.学习/操作 1.获取参数 get方式 【查询字符串方式&#xff1a;Query String】 http://test.oa.com/api/u2d/texture/export?nametest&sex男 Route::get(export, U2dTextureControll…

Laravel最新版的安装(图文)

本文只适合刚接触或者想学Laravel的小白&#xff0c;老鸟就自动略过吧。 Laravel是一套简洁、优雅的PHP WEB开发框架&#xff08;PHP Web Framework&#xff09;&#xff0c;具有富于表达性且简洁的语法&#xff0c;Laravel是易于理解且强大的&#xff0c;它提供了强大的工具用…

Laravel 安装

工作需要&#xff0c;得学习一个php的后台admin管理框架&#xff0c;用于管理内容。这一天都在搜GitHub和gitee&#xff0c;GitHub是真的难访问啊&#xff0c;时断时续的&#xff1b;gitee上有一些&#xff0c;但好多都停更了的样子&#xff0c;有一些还不错的&#xff0c;例如…

Laravel 8 文件的上传/下载/显示的实例

如何实现对文件的操作&#xff0c;实现上传&#xff0c;下载&#xff0c;展示等等功能&#xff0c;我们通过编写一个简单的实例来了解其中具体的内容。 文件列表的展示/文件上传/文件下载 首先我们需要创建两个文件&#xff0c;一个视图文件&#xff0c;一个控制器&#xff0c…

安装laravel

安装laravel之前首先应该设置好安装好php&#xff0c;配置好环境变量。之后安装好compser。 1、安装php环境变量。 我使用的php环境安装包是upupw&#xff0c;&#xff08;php环境安装包有很多&#xff0c;例如phpstudy&#xff0c;wamp等等&#xff0c;读者可自行百度。&…

Laravel框架 -- 文件下载功能

Laravel 文件下载功能&#xff0c;通过手册&#xff0c;我们可以发现&#xff0c;Response的download方法就是我们所需要的文件下载功能的重要元素。 首先&#xff0c;我们注意一下&#xff0c;上面的方法中有两种写法&#xff0c;那么我以第二种为例子&#xff0c;解释一下实际…

laravel安装

文章目录 前言一、下载composer二、安装composercmd 输入composer 检验 三、配置镜像第一步第二步 四、虚拟目录配置 前言 前提&#xff1a;安装了phpStudy套件。https://www.xp.cn/download.html 一、下载composer 从laravel5.x 开始 , 官网https://getcomposer.org/Compose…

laravel文件上传与下载

https://github.com/Chumper/Zippergithub地址 composer require chumper/zipper看到这个代表安装成功 代表路由 . . . // package chumper/zipper Route::get(zip, ZipControllerindex)->name(zip.index); Route::post(zip/download, ZipControllerdownload)->name(zi…

Laravel 5.7下载、安装

本地安装laravel&#xff0c;php环境要配置好&#xff0c;推荐xmapp一键搭建。 1、程序包直接从官方下载&#xff0c;官方开源地址:https://github.com/laravel/laravel(当然也可从此网站&#xff1a;http://www.golaravel.com/download/ 下载一键安装包&#xff0c;下载下来就…

【laravel】laravel的下载安装

下载 Laravel Laravel 利用 Composer&#xff08;Composer 中文&#xff09;来管理其自身的依赖包。因此&#xff0c;在使用 Laravel 之前&#xff0c;请务必确保在你的机器上已经安装了 Composer 。 上面是laravel中文对于如何安装使用laravel的官方解释&#xff0c;不同于大多…