红黑树java代码实现
红黑树 思想源于:https://www.cnblogs.com/nananana/p/10434549.html
有解释有图,很清晰(删除时需考虑根节点和兄弟节点的子节点是否存在)
package tree; import jdk.nashorn.internal.ir.CallNode; import java.util.Random; /**
* 红黑树
* 思想源于:https://www.cnblogs.com/nananana/p/10434549.html
*/
public class RBTree {
private RBTree.Node root = null; private enum Color {RED, BLACK} private enum Child {LEFT, RIGHT} private class Node {
private Integer key; //key
private Object data; //value
private Node leftChild; //左子节点
private Node rightChild; //右子节点
private Node parent; //父节点
private Color color; //红黑标示 private Node() {
} Node(Object key, Object data, Color color) {
this.key = (Integer) key;
this.data = data;
this.color = color;
} public Color getColor() {
return color;
} public void setColor(Color color) {
this.color = color;
} boolean isRed() {
if (this.color.equals(Color.RED))
return true;
return false;
}
} /**
* 插入数据
*
* @param value 插入数据
* @return 数据重复返回false
*/
boolean insertNode(Integer key, Object value) {
return insertNode(root, key, value, null, Child.LEFT);
} private boolean insertNode(Node node, Integer key, Object value, Node preNode, Child child) {
if (node == null) {
node = new Node(key, value, Color.RED);
if (preNode == null) { //父节点为空,将node设为根节点
root = node;
} else {
if (child.equals(Child.LEFT)) {
preNode.leftChild = node;
} else {
preNode.rightChild = node;
}
node.parent = preNode;
} //通过RB_INSERT_FIXUP对红黑树的结点进行颜色修改以及旋转,让树仍然是一颗红黑树
RB_INSERT_FIXUP(node);
return true;
} else {
if (key.compareTo(node.key) == 0) {
//root = node;
return false;
} else if (key.compareTo(node.key) < 0) {
if (!insertNode(node.leftChild, key, value, node, Child.LEFT)) {
return false;
}
} else {
if (!insertNode(node.rightChild, key, value, node, Child.RIGHT)) {
return false;
}
}
return true;
}
} /**
* @param node 插入节点
*/
private void RB_INSERT_FIXUP(Node node) {
Node pNode = node.parent;
if (node == root) { //插入结点为跟节点,直接改变颜色
node.setColor(Color.BLACK);
return;
}
if (node == null || pNode.color.equals(Color.BLACK)) { //插入结点的父结点为黑结点,由于插入的结点是红色的,并不会影响红黑树的平衡,直接插入即可,无需做自平衡。
return;
} else { //情景4:插入结点的父结点为红结点
Node graNode = node.parent.parent;
if (pNode == graNode.leftChild) { //父节点是祖父节点的左子节点
if (graNode.rightChild != null && graNode.rightChild.isRed()) { //情景4.1:叔叔结点存在并且为红结点
/*将P和S设置为黑色(当前插入结点I)将gra设置为红色 把gra设置为当前插入结点*/
pNode.setColor(Color.BLACK);
graNode.rightChild.setColor(Color.BLACK);
graNode.setColor(Color.RED);
RB_INSERT_FIXUP(graNode);
} else { //情景4.2:叔叔结点不存在或为黑结点,并且插入结点的父亲结点是祖父结点的左子结点
if (node == pNode.leftChild) {//情景4.2.1 插入结点是其父结点的左子结点
/*将P设为黑色 将gra设为红色 对gra进行右旋*/
pNode.setColor(Color.BLACK);
graNode.setColor(Color.RED);
RRotate(graNode);
} else { //情景4.2.2 插入结点是其父结点的右子结点
/*对P进行左旋 把P设置为插入结点,得到情景4.2.1 进行情景4.2.1的处理*/
LRotate(pNode);
RB_INSERT_FIXUP(pNode);
} }
} else { //4.3 父节点是祖父节点的右子节点
if (graNode.leftChild != null && graNode.leftChild.isRed()) { //情景4.3:叔叔结点存在并且为红结点+
/*将P和S设置为黑色(当前插入结点I)将gra设置为红色 把gra设置为当前插入结点*/
pNode.setColor(Color.BLACK);
graNode.leftChild.setColor(Color.BLACK);
graNode.setColor(Color.RED);
RB_INSERT_FIXUP(graNode);
} else { //情景4.3.1:叔叔结点不存在或为黑结点,并且插入结点的父亲结点是祖父结点的左子结点
if (node == pNode.rightChild) {//情景4.3.1:插入结点是其父结点的右子结点
/*将P设为黑色 将gra设为红色 对PP进行左旋*/
pNode.setColor(Color.BLACK);
graNode.setColor(Color.RED);
LRotate(graNode);
} else { //情景4.3.2 插入结点是其父结点的右子结点
/*对P进行右旋 把P设置为插入结点,得到情景4.3.1 进行情景4.3.1的处理*/
RRotate(pNode);
RB_INSERT_FIXUP(pNode);
}
}
}
}
} /**
* 右旋
*
* @param T
*/
private void RRotate(Node T) {
Node lc = T.leftChild;
T.leftChild = lc.rightChild;
if (T.leftChild != null) {
T.leftChild.parent = T;
}
lc.rightChild = T;
returnPNode(T, lc);
} private Node returnPNode(Node T, Node node) {
if (T == root) {
root = node;
} else if (T.parent.leftChild == T) {
T.parent.leftChild = node;
} else {
T.parent.rightChild = node;
}
node.parent = T.parent;
T.parent = node;
return node;
} /**
* 左旋
*
* @param T
*/
private void LRotate(Node T) {
Node rc = T.rightChild;
T.rightChild = rc.leftChild;
if (T.rightChild != null) { T.rightChild.parent = T;
}
rc.leftChild = T;
returnPNode(T, rc);
} /**
* 中序
*/
public void ldrTraversal() {
ldrTraversal(root);
} /**
* 中序
*/
private void ldrTraversal(Node node) {
if (node != null) {
ldrTraversal(node.leftChild);
System.out.print(node.key + ":" + node.color + ";");
//System.out.print("key:" + node.key + "-value" + node.data + ":" + node.color + ";");
ldrTraversal(node.rightChild);
} } /**
* 先序
*/
public void dlrTraversal() {
dlrTraversal(root);
} /**
* 先序
*/
private void dlrTraversal(Node node) {
if (node != null) {
System.out.print(node.key + ":" + node.color + ";");
dlrTraversal(node.leftChild);
dlrTraversal(node.rightChild);
} } /**
* 后序
*/
public void lrdTraversal() {
lrdTraversal(root);
} /**
* 后序
*/
private void lrdTraversal(Node node) {
if (node != null) {
lrdTraversal(node.leftChild);
lrdTraversal(node.rightChild);
System.out.print("key:" + node.key + "-value" + node.data + ":" + node.color + ";");
} } /**
* 搜索
*
* @param key 传入key
* @return 返回value
*/
public Object search(Integer key) {
if (this.root != null) {
return searchNode(key, root).data;
}
return null;
} /**
* @param key 删除key对应的node
*/
public boolean removen(Integer key) {
if (this.root != null) {
Node node = searchNode(key, root);
if (node == null) {
return false;
}
removenNode(node);
return true;
}
return false;
} /**
* @param node 删除的节点
*/
private void removenNode(Node node) {
if (node == null) {
return;
}
if (node.leftChild == null && node.rightChild == null) { //情景1:若删除结点无子结点,直接删除。
changeNode(node, null);
} else if (node.leftChild != null && node.rightChild != null) { //情景3:若删除结点有两个子结点,用后继结点(大于删除结点的最小结点)替换删除结点。
Node rNode = node.rightChild;
while (rNode.leftChild != null) { //找到后继结点
rNode = rNode.leftChild;
}
// 交换位子
/*if (rNode == node.rightChild) {
node.rightChild = null;
rNode.leftChild = node.leftChild;
} else {
if (rNode.rightChild != null) { //后继节点如果有右节点
rNode.parent.leftChild = rNode.rightChild;
rNode.rightChild.parent = rNode.parent;
}
rNode.leftChild = node.leftChild;
rNode.rightChild = node.rightChild;
}*/
changeNode(node, rNode); //用后继节点替换要删除节点
} else { //情景2:若删除结点只有一个子结点,用子结点替换删除结点。
if (node.leftChild != null) {
changeNode(node, node.leftChild);
} else {
changeNode(node, node.rightChild);
}
}
} /**
* 两节点位置交换
* 交换后删除替换节点fixupNode
* @param delNode 要删除节点
* @param fixupNode 替换节点
*/
private void changeNode(Node delNode, Node fixupNode) {
RB_DELETE_FIXUP(fixupNode); if (fixupNode == null) {
if (delNode.parent.leftChild == delNode) {
delNode.parent.leftChild = null;
} else {
delNode.parent.rightChild = null;
}
return;
} Object data = delNode.data;
Color color = delNode.color;
Integer key = delNode.key;
if (delNode == root) { // 交换时如果删除节点是根节点,颜色直接改成黑色
delNode.setColor(Color.BLACK);
} else {
delNode.color = fixupNode.color;
}
delNode.key = fixupNode.key;
delNode.data = fixupNode.data;
fixupNode.key = key;
fixupNode.data = data;
fixupNode.color = color; removenNode(fixupNode);
} public Node searchNode(Integer key, Node node) {
if (node == null)
return null;
if (node.key.compareTo(key) == 0) {
return node;
} else if (key.compareTo(node.key) < 0) {
if (node.leftChild != null) {
return searchNode(key, node.leftChild);
}
return null;
} else {
if (node.rightChild != null) {
return searchNode(key, node.rightChild);
}
return null;
}
} private void RB_DELETE_FIXUP(Node fixupNode) {
if (fixupNode == null || fixupNode.isRed()) { //情景1:替换结点是红色结点
/*颜色变为删除结点的颜色*/
return;
} else { //情景2:替换结点是黑结点
Node bNode = fixupNode.parent.rightChild;
if (fixupNode == fixupNode.parent.leftChild) { //情景2.1:替换结点是其父结点的左子结点
//情景2.1.1:替换结点的兄弟结点是红结点
if (bNode.isRed()) {
bNode.setColor(Color.BLACK);
fixupNode.parent.setColor(Color.RED);
RRotate(fixupNode.parent);
RB_DELETE_FIXUP(fixupNode);
} else { //情景2.1.2: 替换结点的兄弟结点是黑结点
//情景2.1.2.1:替换结点的兄弟结点的右子结点是红结点,左子结点任意颜色
if (bNode.rightChild != null && bNode.rightChild.isRed()) {
/*将S的颜色设为P的颜色 将P设为黑色 将SR设为黑色 对P进行左旋*/
bNode.color = fixupNode.parent.color;
fixupNode.parent.setColor(Color.BLACK);
bNode.rightChild.setColor(Color.RED);
LRotate(fixupNode.parent);
} else if (bNode.leftChild != null && bNode.leftChild.isRed()) {
//情景2.1.2.2:替换结点的兄弟结点的右子结点为黑结点,左子结点为红结点
/*将S设为红色 将SL设为黑色 对S进行右旋,得到情景2.1.2.1 进行情景2.1.2.1的处理*/
bNode.setColor(Color.RED);
bNode.leftChild.setColor(Color.BLACK);
RRotate(bNode);
RB_DELETE_FIXUP(fixupNode);
} else {//删除情景2.1.2.3: 替换结点的兄弟结点的子结点都为黑结点
/*将S设为红色 把P作为新的替换结点 重新进行删除结点情景处理*/
bNode.setColor(Color.RED);
RB_DELETE_FIXUP(fixupNode.parent);
} }
} else {
//删除情景2.2: 替换结点是其父结点的右子结点
//删除情景2.2.1: 替换结点的兄弟结点是红结点
if (bNode.isRed()) {
/*将S设为黑色 将P设为红色 对P进行右旋,得到情景2.2.2.3 进行情景2.2.2.3的处理*/
bNode.setColor(Color.BLACK);
fixupNode.parent.setColor(Color.RED);
LRotate(fixupNode.parent);
RB_DELETE_FIXUP(fixupNode);
} else { //删除情景2.2.2: 替换结点的兄弟结点是黑结点
//删除情景2.2.2.1: 替换结点的兄弟结点的左子结点是红结点,右子结点任意颜色
if (bNode.leftChild != null && bNode.leftChild.isRed()) {
/*将S的颜色设为P的颜色 将P设为黑色 将SL设为黑色 对P进行右旋*/
bNode.color = fixupNode.parent.color;
fixupNode.parent.setColor(Color.BLACK);
bNode.leftChild.setColor(Color.BLACK);
RRotate(fixupNode.parent);
} else if (bNode.rightChild != null && bNode.rightChild.isRed()) {//删除情景2.2.2.2: 替换结点的兄弟结点的左子结点为黑结点,右子结点为红结点
/*将S设为红色 将SR设为黑色 对S进行左旋,得到情景2.2.2.1 进行情景2.2.2.1的处理*/
bNode.setColor(Color.RED);
bNode.rightChild.setColor(Color.BLACK);
LRotate(bNode);
RB_DELETE_FIXUP(fixupNode);
} else {//删除情景2.2.2.3:替换结点的兄弟结点的子结点都为黑结点
/*将S设为红色 把P作为新的替换结点 重新进行删除结点情景处理*/
bNode.setColor(Color.RED);
RB_DELETE_FIXUP(fixupNode.parent);
}
}
}
}
} public static void main(String[] args) {
//int[] data={8,6,4};
//int[] data={8,6,9,5,7,3};
//int[] data={8,6,7};
//int[] data={8,5,9,4,6,7};
//int[] data={8,5,9,4,7,6};
//int[] data = {8, 5, 9, 7, 6};
//Object[] data = new Object[100];
//Object[] data = {2, 4, 15, 11, 19, 3, "F", "G", "B", "A", "D", "C", "E", new Person("小王", 22)};
/*for (int i = 0; i < 100; i++) {
Random r = new Random();
int n = r.nextInt(100);
data[i] = "数据" + n;
//System.out.println(n);
}*/
RBTree rbt = new RBTree();
int[] data = {2, 4, 15, 11, 19, 3, 12, 14, 16, 9, 13, 17, 7, 8, 5, 1, 18, 6};
for (int i = 0; i < data.length; i++) {
if (data[i] == 9) {
System.out.println();
}
System.out.println(data[i]);
rbt.insertNode(data[i], data[i]);
rbt.dlrTraversal();
System.out.println("\n" + rbt.root.data);
}
rbt.removen(6);
/*for (int i = 0; i < data.length; i++) {
rbt.insertNode(String.valueOf(i), data[i]);
}*/
rbt.ldrTraversal();
System.out.println("\n" + rbt.root.data);
rbt.dlrTraversal();
//System.out.println("\n" + rbt.search("0"));
}
}
红黑树java代码实现的更多相关文章
- 红黑树 Java实现
概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...
- 第十四章 红黑树——C++代码实现
红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...
- 红黑树 - C++代码实现
红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...
- 【数据结构】红黑树-Java实现
WIKI:https://en.wikipedia.org/wiki/Red%E2%80%93black_tree 转:红黑树(五)之 Java的实现 总结的比较精炼的: http://www.cnb ...
- 高级搜索树-红黑树(RBTree)代码实现
代码实现 代码参考了<数据结构(c++语言版)>--清华大学邓俊辉 "RBTree.h" #pragma once //#include"pch.h" ...
- 红黑树插入与删除完整代码(dart语言实现)
之前分析了红黑树的删除,这里附上红黑树的完整版代码,包括查找.插入.删除等.删除后修复实现了两种算法,均比之前的更为简洁.一种是我自己的实现,代码非常简洁,行数更少:一种是Linux.Java等源码版 ...
- java——红黑树 RBTree
对于完全随机的数据,普通的二分搜索树就很好用,只是在极端情况下会退化成链表. 对于查询较多的情况,avl树很好用. 红黑树牺牲了平衡性,但是它的统计性能更优(综合增删改查所有的操作). 红黑树java ...
- 从二叉查找树到平衡树:avl, 2-3树,左倾红黑树(含实现代码),传统红黑树
参考:自平衡二叉查找树 ,红黑树, 算法:理解红黑树 (英文pdf:红黑树) 目录 自平衡二叉树介绍 avl树 2-3树 LLRBT(Left-leaning red-black tree左倾红黑树 ...
- 对一致性Hash算法,Java代码实现的深入研究
一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...
随机推荐
- Python生成通用唯一识别码UUID
from uuid import uuid4 for i in range(100): uid = str(uuid4()) suid = ''.join(uid.split('-')) print( ...
- CSS遮罩层简易写法
现在很多站点弹出框,都需要一个遮罩层.写法很多,以下是我比较喜欢的一种: .box{ position:absolute; top:0; bottom:0; left:0; right:0; ba ...
- spring(三):DefaultListableBeanFactory
- 基于Docker的Mysql Cluster集群
参考 mysql-cluster镜像 https://medium.com/@ahmedamedy/mysql-clustering-with-docker-611dc28b8db7 使用Docker ...
- DBContext基础查询
https://www.cnblogs.com/gosky/p/5752001.html 遍历所有实体 //遍历所有学生 DBSet using (var db = new Entities()) { ...
- Java多线程wait和notify协作,按序打印abc
有一个经典的多线程面试题:启三个线程,按序打印ABC 上代码: package cn.javaBase.study_thread1; class MyRunnable1 implements Runn ...
- 阻塞队列BlockingQueue之ASynchronousQueue
一.SynchronousQueue简介 Java 6的并发编程包中的SynchronousQueue是一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的移除 ...
- 每天进步一点点------Allegro 原理图到PCB网表导入
- Modelsim, Debussy联合仿真Xilinx
http://wenku.baidu.com/view/8363d40003d8ce2f006623e9.html 另外一个博客 生成Xilinx库 先调用ISE的simulation librar ...
- 题解 UVA1335 【Beijing Guards】
UVA1335 Beijing Guards 双倍经验:P4409 [ZJOI2006]皇帝的烦恼 如果只是一条链,第一个护卫不与最后一个护卫相邻,那么直接贪心,找出最大的相邻数的和. 当变成环,贪心 ...