红黑树规则
- 1.每一个节点不是红色就是黑色的
- 2.根节点总是黑色的
- 3.如果节点是红色,则它的子节点必须是黑色,反之则不一定
- 4.从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点
- 5.空节点默认看成黑色,新添加的节点默认为红色节点
package com.at.tree;
import java.util.LinkedList;
import java.util.Queue;
/**
* 红黑树
* 1.每一个节点不是红色就是黑色的
* 2.根节点总是黑色的
* 3.如果节点是红色,则它的子节点必须是黑色,反之则不一定
* 4.从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点
* 5.空节点默认看成黑色,新添加的节点默认为红色节点
*/
public class RedBlackTree<T extends Comparable<T>> {
/**
* 根节点
*/
private Node<T> root;
/**
* 红-黑树添加节点
*/
public boolean add(T data){
//新的节点 -- 默认红色
Node<T> newNode = new Node<>(data);
//判断是否为根节点
if (root == null){
root = newNode;
root.color = Color.BLACK;//将根节点的颜色该为黑色
return true;
}
//非根节点
Node<T> node = root;
while (true){
//1.下行查找过程中进行颜色的变换
changeColorNode(node);
if (newNode.data.compareTo(node.data) >= 0){
//newNode >= node
if (node.rightNode != null){
node = node.rightNode;
}else {
node.rightNode = newNode;
newNode.parentNode = node;
//插入之后的恢复规则
if (node.color == Color.RED){
//获得祖父节点
Node gpNode = node.parentNode;
if (gpNode.leftNode == node){
//内侧子孙
changeColor(gpNode);
changeColor(newNode);
leftRotate(node);
rightRotate(gpNode);
}else {
//外侧子孙
changeColor(gpNode);
changeColor(node);
leftRotate(gpNode);
}
}
break;
}
}else if (newNode.data.compareTo(node.data) < 0){
//newNode < node
if (node.leftNode != null){
node = node.leftNode;
}else {
node.leftNode = newNode;
newNode.parentNode = node;
//插入之后的恢复规则
if (node.color == Color.RED){
//获得祖父节点
Node gpNode = node.parentNode;
if (gpNode.leftNode == node){
//外侧子孙
changeColor(gpNode);
changeColor(node);
rightRotate(gpNode);
}else {
//内侧子孙
changeColor(gpNode);
changeColor(newNode);
rightRotate(node);
leftRotate(gpNode);
}
}
break;
}
}
}
return true;
}
/**
* 变换节点的颜色,当黑色节点有两个红色子节点的时候
*/
private void changeColorNode(Node<T> node){
if (node.leftNode != null &&
node.rightNode != null &&
node.leftNode.color == Color.RED &&
node.rightNode.color == Color.RED){
//颜色变换
changeColor(node);
changeColor(node.leftNode);
changeColor(node.rightNode);
//是否发生了红-红冲突
Node<T> pNode = node.parentNode;
if (pNode == null){
//说明node本身就是根节点,根节点的原则就是必须为黑色
node.color = Color.BLACK;
}else if (pNode.color == Color.RED){
//红-红冲突
//获得祖父节点
Node<T> gpNode = pNode.parentNode;
//判断node是gpNode的外侧子孙还是内侧子孙
if (gpNode.leftNode == pNode){
if (pNode.leftNode == node){
//外侧子孙,靠左
//1、修改gpNode的颜色
changeColor(gpNode);
//2、修改pNode的颜色
changeColor(pNode);
//3、以gpNode为顶点进行右旋
rightRotate(gpNode);
}else {
//内测子孙,靠左
//1.修改gpNode的颜色
changeColor(gpNode);
//2.修改node的颜色
changeColor(node);
//3.以pNode为顶点进行左旋
leftRotate(pNode);
//4.以gpNode为顶点进行右旋
rightRotate(gpNode);
}
}else{
if (pNode.rightNode == node){
//外侧子孙,靠右
//1、修改gpNode的颜色
changeColor(gpNode);
//2、修改pNode的颜色
changeColor(pNode);
//3、以gpNode为顶点进行左旋
leftRotate(gpNode);
}else {
//内侧子孙,靠右
//1.修改gpNode的颜色
changeColor(gpNode);
//2.修改node的颜色
changeColor(node);
//3.以pNode为顶点进行右旋
rightRotate(pNode);
//4.以gpNode为顶点进行左旋
leftRotate(gpNode);
}
}
}
}
}
/**
* 右旋
* 以a为顶点右旋
* a b
* / \ / \
* b c d a
* / \ -> / / \
* d e f e c
* /
* f
*/
private void rightRotate(Node<T> node){
//获得node的左子树
Node<T> lNode = node.leftNode;
//获得node的父节点
Node<T> pNode = node.parentNode;
//处理旋转的父级节点
if (pNode == null){
this.root = lNode;
}else {
if (pNode.leftNode == node){
pNode.leftNode = lNode;
}else {
pNode.rightNode = lNode;
}
}
lNode.parentNode = pNode;
//处理lNode的右节点
if (lNode.rightNode != null){
node.leftNode = lNode.rightNode;
lNode.rightNode.parentNode = node;
}else {
node.leftNode = null;
}
lNode.rightNode = node;
node.parentNode = lNode;
}
/**
* 右旋
* 以a为顶点左旋
* a c
* / \ / \
* b c a f
* / / \ -> / \ \
* d e f b e g
* \ /
* g d
*/
private void leftRotate(Node<T> node){
//获得node的左子树
Node<T> rNode = node.rightNode;
//获得node的父节点
Node<T> pNode = node.parentNode;
//处理旋转的父级节点
if (pNode == null){
this.root = rNode;
}else {
if (pNode.leftNode == node){
pNode.leftNode = rNode;
}else {
pNode.rightNode = rNode;
}
}
rNode.parentNode = pNode;
//处理lNode的右节点
if (rNode.leftNode != null){
node.rightNode = rNode.leftNode;
rNode.leftNode.parentNode = node;
}else {
node.rightNode = null;
}
rNode.leftNode = node;
node.parentNode = rNode;
}
/**
* 红黑树节点
* @param <T>
*/
private static class Node<T extends Comparable<T>>{
T data;//节点的数据
Color color = Color.RED;//节点的颜色
Node<T> parentNode;//父节点的引用
Node<T> leftNode;//左子树的引用
Node<T> rightNode;//右子树的引用
public Node(T data){
this.data = data;
}
}
/**
* 颜色的枚举
*/
private static enum Color{
RED,
BLACK;
}
/**
* 层次遍历
*/
public void cencibianli(){
System.out.println("------------层次遍历-------------");
//定义一个节点队列
Queue<Node<T>> queue = new LinkedList<>();
queue.add(this.root);
while (true){
Node<T> node = queue.poll();
if (node == null){
break;
}
System.out.println(node.data + ":" + node.color);
if (node.leftNode != null){
queue.add(node.leftNode);
}
if (node.rightNode != null){
queue.add(node.rightNode);
}
}
}
/**
* 转换节点颜色
* @param node
*/
private void changeColor(Node<T> node){
if (node.color == Color.RED){
node.color = Color.BLACK;
}else {
node.color = Color.RED;
}
}
}
package com.at.tree;
public class Client {
public static void main(String[] args) {
RedBlackTree<Integer> redBlackTree = new RedBlackTree<>();
redBlackTree.add(78);
redBlackTree.add(14);
redBlackTree.add(12);
redBlackTree.add(4);
redBlackTree.add(7);
redBlackTree.add(90);
redBlackTree.add(24);
redBlackTree.add(1);
redBlackTree.cencibianli();
}
}