概念:
二叉树:每个节点最多只能有2个子节点。
叶子节点:没有子节点的节点。
二叉搜索树:左节点小于父节点,父节点小于有节点(便于查找)
中序遍历:左节点--> 中(根)节点 --> 右节点(结果是从小到大的顺序)
缺点:极端情况下会变成线性链表,效率底下。
平衡树(AVL树):避免二叉搜索树的致命缺点。
具有二叉搜索树的全部特点
每个节点的左子树和右子树的高度相差最多为1
缺点:会频繁的左右旋。
红黑树:并不是一个完美的平衡二叉搜索树
性质 每个节点要么是黑色要么是红色
根节点是黑色
每个叶子节点是黑色
每个红色节点的两个子节点一定都是黑色
任意一个节点到每个叶子节点的路径都包含相同数量的黑色节点。
如果一个节点存在黑子节点,那么该节点肯定有两个子节点
变色:节点的颜色由红变黑,由黑变红。
左旋:以某个节点作为支点(旋转节点),其右子节点变为旋转节点的父节点,右子节点的左子节点变为旋转节点的右子节点,左子节点保持不变。
右旋:以某个节点作为支点(旋转节点),其左子结点变为旋转节点的父节点,左子节点的右子节点变为旋转节点的左子节点,右子节点保持不变。
插入
新插入的节点是红色(根节点是黑节点)。插入相同的值执行覆盖更新操作。
插入节点的父节点是黑色,直接插,不会影响平衡。
插入节点的父节点是红色,且叔叔节点是红色 ---》
父节点和叔叔节点变为黑色,父父节点变为红色,以爷爷为当前节点,继续操作,直到完成平衡
插入节点的的父节点是红色且叔叔节点不存在,或者为黑色,并且插入节点的父节点是父父节点的左子节点,且插入的节点是左子节点(LL双红)---》
将父节点变为黑色,父父节点变为红色并且对父父节点右旋。
插入节点的父节点是红色且叔叔节点不存在,或者为黑色,并且插入节点的父节点是父父节点的左子节点,且插入的节点是右子节点(LR双红)---》
父节点左旋得到LL双红,处理LL双红。
插入节点的父节点是红色且叔叔节点不存在,或者为黑色,并且插入节点的父节点是父父节点的右子节点,且插入的节点是右子节点(RR双红)---》
父节点变黑,父父节点变红,左旋父父节点
插入节点的父节点是红色且叔叔节点不存在,或者为黑色,并且插入节点的父节点是父父节点的右子节点,且插入的节点是左子节点(RL双红)---》
父节点右旋,处理RR双红。
手写红黑树:删除、打印方法后续补充
package RBTree;
public class RBTree {
// 根节点
private RBNode root;
static class RBNode<V extends Comparable> {
private V value;
private RBNode<V> parent;
private RBNode<V> left;
private RBNode<V> right;
private boolean isRed;
public RBNode() {
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public RBNode<V> getParent() {
return parent;
}
public void setParent(RBNode<V> parent) {
this.parent = parent;
}
public RBNode<V> getLeft() {
return left;
}
public void setLeft(RBNode<V> left) {
this.left = left;
}
public RBNode<V> getRight() {
return right;
}
public void setRight(RBNode<V> right) {
this.right = right;
}
public boolean isRed() {
return isRed;
}
public void setRed(boolean red) {
isRed = red;
}
}
/**
* 获取当前节点的父节点
* @param node
* @return
*/
public RBNode getParent(RBNode node) {
if(node != null){
return node.getParent();
}
return null;
}
/**
* 获取当前节点的左子节点
* @param node
* @return
*/
public RBNode getChildLeft(RBNode node){
if(node != null){
return node.getLeft();
}
return null;
}
/**
* 获取节点的右子节点
* @param node
* @return
*/
public RBNode getChildRight(RBNode node){
if(node != null){
return node.getRight();
}
return null;
}
/**
* 获取当前节点颜色
* @param node
* @return true:红色 false:黑色
*/
public boolean getColor(RBNode node){
if (node != null){
return node.isRed();
}
throw new RuntimeException("node is null");
}
/**
* 设置节点颜色
* @param node
* @param isRed true:红色 false:黑色
*/
public void setColor(RBNode node, boolean isRed){
if (node != null){
node.setRed(isRed);
}
}
/**
* 中序遍历
* @param node
*/
public void printTree(RBNode node){
if (node != null){
printTree(node.getLeft());
System.out.println(node.getValue());
printTree(node.getRight());
}
}
// 左旋:该点右子节点变为父节点,该点右子节点的左子节点变为该节点右子节点
public void leftRotate(RBNode node){
if (node != null){
Comparable value = node.getValue();
RBNode parent = node.getParent();
RBNode right = node.getRight();
RBNode rightChildLeft = right.getLeft();
Comparable parentLeftChildValue = parent.getLeft().getValue();
Comparable parentRightChildValue = parent.getRight().getValue();
if(value.compareTo(parentLeftChildValue) == 0){
parent.setLeft(right);
}
if(value.compareTo(parentRightChildValue) == 0){
parent.setRight(right);
}
right.setParent(parent);
node.setRight(rightChildLeft);
rightChildLeft.setParent(node);
right.setLeft(node);
node.setParent(right);
}
}
// 右旋:该节点左子节点变为父节点,该节点左子节点的右子节点变为该节点左子节点
public void rightRotate(RBNode node){
if (node != null){
Comparable value = node.getValue();
RBNode parent = node.getParent();
RBNode left = node.getLeft();
RBNode leftChildRight = left.getRight();
Comparable parentLeftChildValue = parent.getLeft().getValue();
Comparable parentRightChildValue = parent.getRight().getValue();
if(value.compareTo(parentLeftChildValue) == 0){
parent.setLeft(left);
}
if(value.compareTo(parentRightChildValue) == 0){
parent.setRight(left);
}
left.setParent(parent);
left.setParent(node);
node.setParent(left);
node.setLeft(leftChildRight);
leftChildRight.setParent(node);
}
}
// 插入:找父节点
public void insert(RBNode node){
RBNode parent = null;
RBNode tempParent = root;
while (tempParent != null){
parent = tempParent;
int cmp = node.getValue().compareTo(parent.getValue());
if(cmp > 0){
// node > parent
tempParent = parent.getRight();
}else if(cmp > 0){
// node < parent
tempParent = parent.getLeft();
}else{
tempParent.setValue(node.getValue());
return;
}
}
if(root == null){
node.parent = null;
root = node;
return;
}else {
node.setParent(parent);
}
// 判断作为左子节点还是右子节点
int cmp = node.getValue().compareTo(parent.getValue());
if(cmp > 0){
parent.setRight(node);
}else if(cmp < 0){
parent.setLeft(node);
}
// 修复红黑树的平衡
fixBalance(node);
}
/**
* 插入后修复红黑树的平衡
* 情景1: 红黑树为空树,将跟节点染色为黑色
* XXX情景2: 插入节点的key已经存在,替换已在插入完成,此处不需要处理
* XXX情景3: 插入节点的父节点为黑色,不影响红黑树的特性,所以红黑树依然平衡,所以不需要处理。
* 情景4需要咱们去处理
* |---情景4: 插入节点的父节点为红色
* |---情景4.1: 叔叔节点存在,并且为红色(父-叔 双红)
* |---情景4.2: 叔叔节点不存在,或者为黑色,父节点为爷爷节点的左子树
* |---情景4.2.1: 插入节点为其父节点的左子节点(LL情况)
* |---情景4.2.2: 插入节点为其父节点的右子节点(LR情况)
* |---情景4.3: 叔叔节点不存在,或者为黑色,父节点为爷爷节点的右子树
* |---情景4.3.1: 插入节点为其父节点的右子节点( RR情况)
* |---情景4.3.2: 插入节点为其父节点的左子节点(RL情况)
*/
public void fixBalance(RBNode node){
if(node.parent == null){
// 情景1
node.setRed(false);
}else if (node.parent.isRed == false){
// 情景3
}else {
// 情景4
RBNode parent = node.getParent();
RBNode grandParent = parent.getParent();
RBNode uncle;
if (parent == grandParent.left){
uncle = grandParent.getRight();
if(uncle != null && uncle.isRed()){
// 情景4.1
setColor(parent, false);
setColor(uncle, false);
setColor(grandParent, true);
fixBalance(grandParent);
return;
}else {
if(node == parent.left){
// 情景4.2.1
setColor(parent, false);
setColor(grandParent, true);
rightRotate(grandParent);
return;
}else if (node == parent.right){
// 情景4.2.2
leftRotate(parent);
fixBalance(parent);
return;
}
}
}else if (parent == grandParent.right){
uncle = grandParent.getLeft();
if(uncle != null && uncle.isRed()){
// 情景4.1
setColor(parent, false);
setColor(uncle, false);
setColor(grandParent, true);
fixBalance(grandParent);
return;
}else {
if(node == parent.right){
// 情景4.3.1
setColor(parent, false);
setColor(grandParent, true);
leftRotate(grandParent);
return;
}
if (node == parent.left){
// 情景4.3.2
rightRotate(parent);
fixBalance(parent);
return;
}
}
}
}
}
}