java实现红黑树

news/2024/11/25 19:31:25/

红黑树

红黑树是一种自平衡二叉查找树,其中每个节点都有一个颜色属性,颜色为红色或黑色。它的特性保证了树在插入和删除操作后仍然保持大致的平衡,使得查找操作能够在对数时间内完成。以下是红黑树的一些基本性质:

  1. 每个节点是红色或黑色。
  2. 根节点是黑色。
  3. 所有叶子(NIL节点)都是黑色。
  4. 每个红色节点的两个子节点都是黑色的(从每个叶子到根的所有路径上不能有两个连续的红色节点)。
  5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

请添加图片描述

以下是红黑树的核心代码解析:

public class RedBlackTree {enum Color {RED, BLACK;}Node root;static class Node {int key;Object value;Node left;Node right;Node parent;        // 父节点Color color = RED;  // 默认插入的节点为红色// 构造函数和辅助函数}

构建节点和辅助函数

static class Node {// 构造函数,用于创建新节点public Node(int key, Object value) {this.key = key;this.value = value;}// 判断当前节点是否为左孩子boolean isLeftChild() {return parent != null && parent.left == this;}// 叔叔Node uncle() {if (parent == null || parent.parent == null) {return null;}if (parent.isLeftChild()) {return parent.parent.right;} else {return parent.parent.left;}}// 兄弟Node sibling() {if (parent == null) {return null;}if (this.isLeftChild()) {return parent.right;} else {return parent.left;}}
}

旋转操作(leftRotate & rightRotate)

为了维持红黑树的平衡性,在插入和删除节点时可能会用到旋转操作。

private void rightRotate(Node pink) {Node parent = pink.parent;Node yellow = pink.left;Node green = yellow.right;if (green != null) {green.parent = pink;}yellow.right = pink;yellow.parent = parent;pink.left = green;pink.parent = yellow;if (parent == null) {root = yellow;} else if (parent.left == pink) {parent.left = yellow;} else {parent.right = yellow;}
}// 左旋
private void leftRotate(Node pink) {Node parent = pink.parent;Node yellow = pink.right;Node green = yellow.left;if (green != null) {green.parent = pink;}yellow.left = pink;yellow.parent = parent;pink.right = green;pink.parent = yellow;if (parent == null) {root = yellow;} else if (parent.left == pink) {parent.left = yellow;} else {parent.right = yellow;}
}

旋转操作的目的是重新分布节点,使得树的高度保持平衡,同时需要更新父节点和子节点的引用。

插入(put)

当向红黑树中插入新节点时,需要保证树的性质不被破坏。插入操作后,可能需要通过一系列的旋转和着色来修正树,保持红黑树的性质。

public void put(int key, Object value) {Node p = root;Node parent = null;while (p != null) {parent = p;if (key < p.key) {p = p.left;} else if (p.key < key) {p = p.right;} else {p.value = value; // 更新return;}}Node inserted = new Node(key, value);if (parent == null) {root = inserted;} else if (key < parent.key) {parent.left = inserted;inserted.parent = parent;} else {parent.right = inserted;inserted.parent = parent;}fixRedRed(inserted);
}void fixRedRed(Node x) {// case 1 插入节点是根节点,变黑即可if (x == root) {x.color = BLACK;return;}// case 2 插入节点父亲是黑色,无需调整if (isBlack(x.parent)) {return;}/* case 3 当红红相邻,叔叔为红时需要将父亲、叔叔变黑、祖父变红,然后对祖父做递归处理*/Node parent = x.parent;Node uncle = x.uncle();Node grandparent = parent.parent;if (isRed(uncle)) {parent.color = BLACK;uncle.color = BLACK;grandparent.color = RED;fixRedRed(grandparent);return;}// case 4 当红红相邻,叔叔为黑时if (parent.isLeftChild() && x.isLeftChild()) { // LLparent.color = BLACK;grandparent.color = RED;rightRotate(grandparent);} else if (parent.isLeftChild()) { // LRleftRotate(parent);x.color = BLACK;grandparent.color = RED;rightRotate(grandparent);} else if (!x.isLeftChild()) { // RRparent.color = BLACK;grandparent.color = RED;leftRotate(grandparent);} else { // RLrightRotate(parent);x.color = BLACK;grandparent.color = RED;leftRotate(grandparent);}
}

删除(remove)

删除操作是红黑树中比较复杂的部分。在删除节点时,同样需要通过旋转和重新着色操作来保持红黑树的性质。

public void remove(int key) {Node deleted = find(key);if (deleted == null) {return;}doRemove(deleted);
}public boolean contains(int key) {return find(key) != null;
}// 查找删除节点
private Node find(int key) {Node p = root;while (p != null) {if (key < p.key) {p = p.left;} else if (p.key < key) {p = p.right;} else {return p;}}return null;
}// 查找剩余节点
private Node findReplaced(Node deleted) {if (deleted.left == null && deleted.right == null) {return null;}if (deleted.left == null) {return deleted.right;}if (deleted.right == null) {return deleted.left;}Node s = deleted.right;while (s.left != null) {s = s.left;}return s;
}// 处理双黑 (case3、case4、case5)
private void fixDoubleBlack(Node x) {if (x == root) {return;}Node parent = x.parent;Node sibling = x.sibling();// case 3 兄弟节点是红色if (isRed(sibling)) {if (x.isLeftChild()) {leftRotate(parent);} else {rightRotate(parent);}parent.color = RED;sibling.color = BLACK;fixDoubleBlack(x);return;}if (sibling != null) {// case 4 兄弟是黑色, 两个侄子也是黑色if (isBlack(sibling.left) && isBlack(sibling.right)) {sibling.color = RED;if (isRed(parent)) {parent.color = BLACK;} else {fixDoubleBlack(parent);}}// case 5 兄弟是黑色, 侄子有红色else {// LLif (sibling.isLeftChild() && isRed(sibling.left)) {rightRotate(parent);sibling.left.color = BLACK;sibling.color = parent.color;}// LRelse if (sibling.isLeftChild() && isRed(sibling.right)) {sibling.right.color = parent.color;leftRotate(sibling);rightRotate(parent);}// RLelse if (!sibling.isLeftChild() && isRed(sibling.left)) {sibling.left.color = parent.color;rightRotate(sibling);leftRotate(parent);}// RRelse {leftRotate(parent);sibling.right.color = BLACK;sibling.color = parent.color;}parent.color = BLACK;}} else {// @TODO 实际也不会出现,触发双黑后,兄弟节点不会为 nullfixDoubleBlack(parent);}
}private void doRemove(Node deleted) {Node replaced = findReplaced(deleted);Node parent = deleted.parent;// 没有孩子if (replaced == null) {// case 1 删除的是根节点if (deleted == root) {root = null;} else {if (isBlack(deleted)) {// 复杂调整fixDoubleBlack(deleted);} else {// 红色叶子, 无需任何处理}if (deleted.isLeftChild()) {parent.left = null;} else {parent.right = null;}deleted.parent = null;}return;}// 有一个孩子if (deleted.left == null || deleted.right == null) {//  删除的是根节点if (deleted == root) {root.key = replaced.key;root.value = replaced.value;root.left = root.right = null;} else { // 只可能是红节点if (deleted.isLeftChild()) {parent.left = replaced;} else {parent.right = replaced;}replaced.parent = parent;deleted.left = deleted.right = deleted.parent = null;replaced.color = BLACK;}return;}// case 0 有两个孩子 => 有一个孩子 或 没有孩子int t = deleted.key;deleted.key = replaced.key;replaced.key = t;Object v = deleted.value;deleted.value = replaced.value;replaced.value = v;doRemove(replaced);
}

http://www.ppmy.cn/news/1326198.html

相关文章

openssl3.2 - 官方demo学习 - smime - smenc.c

文章目录 openssl3.2 - 官方demo学习 - smime - smenc.c概述笔记END openssl3.2 - 官方demo学习 - smime - smenc.c 概述 读取X509证书, 用PKCS7加密明文(证书 明文 3DES_CBC), 保存为MIME格式的密文 openssl API的命名含义 BIO_new_file “new” a “file”, return a “…

【卡梅德生物】如何制备纳米抗体?

纳米抗体的制备通常涉及到从动物源&#xff08;如骆驼、羊驼&#xff09;提取RNA或cDNA&#xff0c;然后通过分子生物学技术将其克隆并表达。以下是一般的纳米抗体制备步骤&#xff1a; 1.提取RNA或cDNA&#xff1a; -动物源&#xff1a;选择产生纳米抗体的动物&#xff0c;如…

ubuntu qt 运行命令行

文章目录 1.C实现2.python实现 1.C实现 下面是封装好的C头文件&#xff0c;直接调用run_cmd_fun()即可。 #ifndef GET_CMD_H #define GET_CMD_H#endif // GET_CMD_H #include <iostream> #include<QString> using namespace std;//system("gnome-terminal -…

分布式搜索引擎ElasticSearch——深入elasticSearch

分布式搜索引擎ElasticSearch——深入elasticSearch 文章目录 分布式搜索引擎ElasticSearch——深入elasticSearch数据聚合聚合的分类DSL实现Bucket聚合DSL实现Metric聚合RestAPI实现聚合 自动补全DSL实现自动补全查询修改酒店索引库数据结构RestAPI实现自动补全查询实现酒店搜…

scroll-view在小程序页面里实现滚动,uniapp项目

要实现红框中的区域进行滚动,scroll-view必须写高 <template><!-- 合同-待确认 --><view class"viewport"><!-- 上 --><view class"top-box"><!-- tab --><view class"tabs"><textv-for"(ite…

离线数据仓库-关于增量和全量

数据同步策略 数据仓库同步策略概述一、数据的全量同步二、数据的增量同步三、数据同步策略的选择 数据仓库同步策略概述 应用系统所产生的业务数据是数据仓库的重要数据来源&#xff0c;我们需要每日定时从业务数据库中抽取数据&#xff0c;传输到数据仓库中&#xff0c;之后…

什么是技术架构?架构和框架之间的区别是什么?怎样去做好架构设计?(二)

什么是技术架构?架构和框架之间的区别是什么?怎样去做好架构设计?(二)。 技术架构是对某一技术问题(需求)解决方案的结构化描述,由构成解决方案的组件结构及之间的交互关系构成。广义上的技术架构是一系列涵盖多类技术问题设计方案的统称,例如部署方案、存储方案、缓存…

Linux搭建dns主从服务器

一、实验要求 配置Dns主从服务器&#xff0c;能够实现正常的正反向解析 二、知识点 1、DNS简介 DNS&#xff08;Domain Name System&#xff09;是互联网上的一项服务&#xff0c;它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便的访问互联网。…