红黑树
1.红黑树基本的特征介绍
基本特征:
- 每个节点不是红色就是黑色
- 不允许两红相连
- 根节点都是黑色
- 每个红色节点的两个子节点都是黑色
- 默认情况下添加的节点为红色节点
备注:如果产生了红色相连如何解决:变色或者旋转。
红黑树平衡规则:
1.改变节点颜色
2.左旋转
3.右旋转
2.红黑树变换颜色的规则要求
变色或者旋转都是插入节点后修复平衡的实现。
变色:当前节点父亲是红色,叔叔节点(祖父节点的另一个子节点)也是红色:
1.将父亲节点设置为黑色
2.将叔叔节点设为黑色
3.将祖父也就是父亲的父亲设为红色
4.把指针定义到祖父节点设为当前操作
左旋转:当父亲节点为红色情况,叔叔的节点为黑色的情况,且当前的节点是右子树,左旋转以父节点作为左旋;
左旋后祖父节点变为红色,父亲节点变成黑色
右旋转:当父亲节点为红色情况,叔叔的节点为黑色的情况,且当前的节点是左子树,右旋转以
- 父节点作为右旋;
- 将父节点变为黑色
- 将祖父节点变为红色(爷爷)
- 以祖父节点开始旋转
3.红黑树左右旋转基本的规则
4.纯手写红黑树左旋转和变色
/**
*
*/
package com.chenyun.tree;
/**
* @author: 陈云
* @date: 2021年12月13日
* @description:
*/
public class RedBlackTree {
class Node {
/**
* 节点内容值
*/
private int value;
/**
* 节点颜色
*/
private String color;
/**
* 左子树
*/
private Node left;
/**
* 右子树
*/
private Node right;
/**
* 记录当前节点父节点
*/
private Node parent;
public Node(int value, String color, Node left, Node right, Node parent) {
super();
this.value = value;
this.color = color;
this.left = left;
this.right = right;
this.parent = parent;
}
public Node() {
super();
}
@Override
public String toString() {
return "Node [value=" + value + ", color=" + color + ", left=" + left + ", right=" + right + ", parent="
+ parent + "]";
}
}
//记录根节点
private Node root;
/**
* 添加节点
* @param value
* @return
*/
public Node add(int value) {
//当根节点为null时,新插入的节点就是跟节点
if(root == null) {
Node node = new Node(value, "black", null, null, null);
root = node;
return node;
}else {
//当根节点不为空时,从根节点开始,搜索二叉树,得到新节点要插入的位置,并插入新节点
Node node = getPosition(root, value);
//红黑树修复
repairTree(node);
return node;
}
}
/**
* 红黑树修复
* @param node
*/
private void repairTree(Node node) {
//如果父节点为红色,当前节点默认红色,两红相连,变色或者旋转
if(node.parent.color.equals("red") && node.color.equals("red")) {
//父节点
Node p = node.parent;
Node g = node.parent.parent;
//如果叔叔节点和父亲节点都为红,变色操作:将父亲节点+叔叔节点改为黑,祖父节点改为红
//假设当前为右子树,叔叔在左边
if(g.left != null && g.left.color.equals("red")) {
p.color = "black";
g.left.color = "black";
//如果祖父节点为根节点
if(g == root) {
g.color ="black";
}else {
g.color = "red";
}
return;
}
//否则旋转
leftRotate(g);
//左旋后祖父节点变为红色,父亲节点变成黑色
g.color = "red";
p.color = "black";
}
}
/**
* 左旋
* @param x
*/
private void leftRotate(Node x) {
//通过待翻下的x,获取待翻上的y
Node y = x.right;
//改变x和y.left的执行
x.right = y.left;
if(y.left != null) {
y.left.parent = x;
}
//改变父节点指向
y.parent = x.parent;
if(x.parent == null) {
// x为根节点,x翻下y翻上,y变为新根节点
root = y;
}else {
// 否则,判断x为左子树或者右子树,分别做不同的处理
if (x.parent.left == x) {
// x为左子树,父节点的左子树变为y
x.parent.left = y;
} else {
x.parent.right = y;
}
}
// 更改x和y之间的指向关系
y.left = x;
x.parent = y;
}
/**
* 遍历二叉树,把新节点添加到二叉树的末尾
* @param node
* @param value
* @return
*/
private Node getPosition(Node node,int value) {
if(value > node.value) {
//插入右子树
if(node.right == null) {
Node newNode = new Node(value, "red", null, null, node);
node.right = newNode;
return newNode;
}else {
return getPosition(node.right, value);
}
}else {
//插入左子树
if(node.left == null) {
Node newNode = new Node(value, "red", null, null, node);
node.left = newNode;
return newNode;
}else {
return getPosition(node.left, value);
}
}
}
}
5.红黑树查询最大值
/**
* 查询最大值
* @return
*/
public int getMax() {
int maxValue = getMaxValue(root);
return maxValue;
}
/**
* 递归查询最大值
* @param node
* @return
*/
private int getMaxValue(Node node) {
if (node != null) {
if (node.right != null) {
return getMaxValue(node.right);
} else {
return node.value;
}
}
return 0;
}
红黑树查询时间复杂度o(log n)
如果当前有10亿数字,如何最快的查找到最大/小值?
使用红黑树/平衡二叉树,30次左右,2^30=10亿+