红黑树java实现

红黑树的性质

红黑树是一课二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以使RED或BLACK。通过对任何一条从根到叶子的简单路径上各个结点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出2倍,因而是近似平衡的

树中每个结点包含5个属性:color、key、left、right、parent。如果一个结点没有子结点或父结点,则该结点相应属性的值为null。一棵红黑树是满足下面红黑性质的二叉搜索树:

  1. 每个结点或是红色的,或是黑色的;
  2. 根结点是黑色的;
  3. 每个叶结点是黑色的;
  4. 如果一个结点是红色的,则它的两个子结点都是黑色的;
  5. 对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点。

为了便于处理红黑树代码中的边界条件,可以使用一个哨兵来代表null。对于一棵红黑树,哨兵是一个与树中的普通结点有相同属性的对象。它的color属性为BLACK,其他属性可以设置为任意值。如下图所示为一棵使用了哨兵的红黑树示例。
在这里插入图片描述

旋转

当对树执行插入或操作时,对树做了修改,所做的修改可能会导致树不满足红黑树的性质,因此需要进行旋转来维护红黑树的性质。旋转可分为左旋和右旋。下图展示了一棵子树旋转后的结果。
在这里插入图片描述

java代码实现

下面是使用java简单实现了红黑树,以及红黑树的插入和删除操作。

/*** 数据结构-红黑树*/
public class RBTree {/*** 哨兵*/private final Node sentinel = new Node(Color.BLACK);/*** 根节点*/private Node root = sentinel;/*** 根据关键字搜索节点** @param key 关键字* @return key所在的节点*/public Node search(int key) {Node node = root;while (node != null && key != node.key) {// 如果key小于当前节点的key,则往左孩子节点找,否则往右孩子节点找if (key < node.key) {node = node.left;} else {node = node.right;}}return node;}/*** 插入关键字为key的节点** @param key 关键字*/public void insert(int key) {Node y = sentinel;Node x = root;while (x != sentinel) {y = x;if (key < x.key) {x = x.left;} else {x = x.right;}}Node newNode = new Node();newNode.key = key;newNode.parent = y;if (y == sentinel) {root = newNode;} else if (key < y.key) {y.left = newNode;} else {y.right = newNode;}newNode.left = sentinel;newNode.right = sentinel;newNode.color = Color.RED;insertFixUp(newNode);}/*** 删除关键字为key的节点** @param key 关键字*/public void delete(int key) {Node node = search(key);Node y = node;Color yOriginalColor = y.color;Node x;if (node.left == sentinel) {x = node.right;transplant(node, node.right);} else if (node.right == sentinel) {x = node.left;transplant(node, node.left);} else {y = min(node.right);yOriginalColor = y.color;x = y.right;if (y.parent == node) {x.parent = y;} else {transplant(y, y.right);y.right = node.right;y.right.parent = y;}transplant(node, y);y.left = node.left;y.left.parent = y;y.color = node.color;}if (yOriginalColor == Color.BLACK) {deleteFixUp(x);}}/*** 获取以node为根的子树中key最小的节点** @param node 子树根节点* @return 子树中key最小的节点*/public Node min(Node node) {while (node.left != null) {node = node.left;}return node;}public Node getRoot() {return root;}/*** 删除一个节点后,维护树的红黑性质** @param node 节点*/private void deleteFixUp(Node node) {while (node != root && node.color == Color.BLACK) {if (node == node.parent.left) {Node w = node.parent.right;if (w.color == Color.RED) {w.color = Color.BLACK;node.parent.color = Color.RED;leftRotate(node.parent);w = node.parent.right;}if (w.left.color == Color.BLACK && w.right.color == Color.BLACK) {w.color = Color.RED;node = node.parent;} else if (w.right.color == Color.BLACK) {w.left.color = Color.BLACK;w.color = Color.RED;rightRotate(w);w = node.parent.right;}w.color = node.parent.color;node.parent.color = Color.BLACK;w.right.color = Color.BLACK;leftRotate(node.parent);node = root;} else {Node w = node.parent.left;if (w.color == Color.RED) {w.color = Color.BLACK;node.parent.color = Color.RED;leftRotate(node.parent);w = node.parent.left;}if (w.right.color == Color.BLACK && w.left.color == Color.BLACK) {w.color = Color.RED;node = node.parent;} else if (w.left.color == Color.BLACK) {w.right.color = Color.BLACK;w.color = Color.RED;leftRotate(w);w = node.parent.left;}w.color = node.parent.color;node.parent.color = Color.BLACK;w.left.color = Color.BLACK;rightRotate(node.parent);node = root;}}node.color = Color.BLACK;}/*** 将node1替换成node2,以支持删除操作** @param node1 节点1* @param node2 节点2*/private void transplant(Node node1, Node node2) {if (node1.parent == sentinel) {root = node2;} else if (node1 == node1.parent.left) {node1.parent.left = node2;} else {node1.parent.right = node2;}node2.parent = node1.parent;}/*** 插入一个节点后,维护树的红黑性质** @param node 插入的节点*/private void insertFixUp(Node node) {while (node.parent.color == Color.RED) {if (node.parent == node.parent.parent.left) {Node temp = node.parent.parent.right;if (temp.color == Color.RED) {node.parent.color = Color.BLACK;temp.color = Color.BLACK;node.parent.parent.color = Color.RED;node = node.parent.parent;} else if (node == node.parent.right) {node = node.parent;leftRotate(node);} else {node.parent.color = Color.BLACK;node.parent.parent.color = Color.RED;rightRotate(node.parent.parent);}} else {Node temp = node.parent.parent.left;if (temp.color == Color.RED) {node.parent.color = Color.BLACK;temp.color = Color.BLACK;node.parent.parent.color = Color.RED;node = node.parent.parent;} else if (node == node.parent.left) {node = node.parent;rightRotate(node);} else {node.parent.color = Color.BLACK;node.parent.parent.color = Color.RED;leftRotate(node.parent.parent);}}}root.color = Color.BLACK;}/*** 在节点node上进行左旋操作** @param node 节点*/private void leftRotate(Node node) {Node right = node.right;// 将node的右子树的左子树放到node的右子树位置node.right = right.left;if (right.left != sentinel) {right.left.parent = node;}// 设置node的右子树的父节点为node的父节点right.parent = node.parent;if (node.parent == sentinel) {root = right;} else if (node == node.parent.left) {node.parent.left = right;} else {node.parent.right = right;}// 将node放到node的右子树的左子树位置right.left = node;node.parent = right;}/*** 在节点node上进行右旋操作** @param node 节点*/private void rightRotate(Node node) {Node left = node.left;node.left = left.right;if (left.right != sentinel) {left.right.parent = node;}left.parent = node.parent;if (node.parent == sentinel) {root = left;} else if (node == node.parent.right) {node.parent.right = left;} else {node.parent.left = left;}left.right = node;node.parent = left;}private enum Color {/*** 红色*/RED,/*** 黑色*/BLACK}public static class Node {/*** 节点颜色*/private Color color;/*** 节点关键字*/private int key;/*** 左孩子节点*/private Node left;/*** 右孩子节点*/private Node right;/*** 父节点*/private Node parent;private Node() {}private Node(Color color) {this.color = color;}public Color getColor() {return color;}public int getKey() {return key;}public Node getLeft() {return left;}public Node getRight() {return right;}public Node getParent() {return parent;}}
}

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

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

相关文章

php文件上传例子

目录结构&#xff1a; index.html代码&#xff1a; <!DOCTYPE html> <html><head><title>文件上传</title><meta charset"utf-8"></head><body><form action"./up.php" method"post" encty…

基于STM32的手势识别算法研究与应用

基于STM32的手势识别算法在人机交互和智能设备控制中具有重要的应用价值。本文将介绍基于STM32的手势识别算法的研究原理和实现步骤&#xff0c;并提供相应的代码示例。 1. 手势识别概述 手势识别是一种通过分析人体的手部动作和姿势来识别和理解人的意图的技术。基于STM32的…

在PyCharm中正确设置Python项目

大家好&#xff0c;在Mac和Linux都支持Python&#xff0c;但许多开发者发现正确设置Python项目很困难。本文汇总了多平台中运行Python的方法&#xff0c;提高编程的效率&#xff0c;如下所示&#xff1a; 使用命令行运行Python。 在PyCharm&#xff08;免费社区版&#xff09;…

【Web】preg_match绕过相关例题wp

目录 ①[FBCTF 2019]rceservice ②[ctfshow]web130 ③[ctfshow]web131 ④[NISACTF 2022]middlerce 简单回顾一下基础 参考文章 p牛神文 preg_match绕过总的来讲就三块可利用 数组绕过、PCRE回溯次数限制、换行符 ①[FBCTF 2019]rceservice 先贴出附件给的源码 &l…

Linux安装Mysql详细教程(两种安装方法)

Linux之Mysql安装配置 第一种&#xff1a;Linux离线安装Mysql&#xff08;提前手动下载好tar.gz包&#xff09;第二种&#xff1a;通过yum安装配置Mysql&#xff08;服务器有网络&#xff09; 第一种&#xff1a;tar.gz包安装 1、 查看是否已经安装 Mysql rpm -qa | grep m…

VS Code 如何搭建C/C++环境

目录 一、VS Code是什么&#xff1f; 二、VS Code下载和安装 2.1下载 2.2安装 2.3环境介绍 三、Vs Code配置C/C环境 3.1下载和配置MinGW-w64编译器套件 3.1.1下载 3.1.2配置 一、VS Code是什么&#xff1f; 跨平台&#xff0c;免费且开源的现代轻量级代码编辑器 Vis…

MongoDB的常用操作以及python连接MongoDB

一,MongoDB的启动 mongod --dbpath..\data\db mongodb注意同时开两个窗口&#xff0c;不要关&#xff01; 二, MongoDB的简单使用 简单介绍一下mongoDB中一些操作 show dbs: 显示所有数据库 show databases: 显示所有数据库 use xxxx: 使用指定数据库/创建数据库&#xff08…

基于STM32的数字图像处理与模式识别算法优化

基于STM32的数字图像处理与模式识别算法优化是一项涉及图像处理和机器学习领域的研究任务&#xff0c;旨在实现高效的图像处理和模式识别算法在STM32微控制器上的运行。本文将介绍基于STM32的数字图像处理与模式识别算法优化的原理和实现步骤&#xff0c;并提供相应的代码示例。…

关于一些bug的解决1、el-input的输入无效2、搜索之后发现数据不对3、el多选框、单选框点击无用4、

el-input输入无效 原来的代码是 var test null 但是我发现不能输入任何值 反倒修改test的初始值为123是可以的 于是我确定绑定没问题 就是修改的问题 于是改成 var test ref&#xff08;&#xff09; v-model绑定的值改成test.value就可以了 因为ref是相应式的 可以通过输入…

牛客 最小公配数 golang版实现

题目请参考: HJ108 求最小公倍数 题解: 在大的数的倍数里面去找最小的能整除另外一个数的数&#xff0c;就是最小公倍数&#xff0c;按照大的来找&#xff0c;循环次数能够降到很少&#xff0c;提升效率 golang实现: package mainimport ("fmt" )func main() {a : …

【开源】基于Vue.js的天然气工程业务管理系统的设计和实现

项目编号&#xff1a; S 021 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S021&#xff0c;文末获取源码。} 项目编号&#xff1a;S021&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、使用角色3.1 施工人员3.2 管理员 四…

【SpringCloud】认识微服务、服务拆分以及远程调用

SpringCloud 1.认识微服务 1.1单体架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&#xff0c;打成一个包部署 单体架构的优缺点&#xff1a; 优点&#xff1a; 架构简单&#xff0c;部署成本低 缺点&#xff1a; 耦合度高&#xff08;维护困难&#x…