红黑树的作用:
前面我写了一个普通查找二叉树,普通查找二叉树有一个弊端,就是可能会有极坏的情况(节点一边倒,分布不完全)。那么红黑树就是一种特殊的查找二叉树,能让节点尽可能完全分布的情况。
红黑树的定义:
红黑树是具有以下着色性质的二叉查找树:
1.每一个节点不是黑色就是红色
2.根是黑色
3.如果一个节点是红色的,那么它的子节点必须是黑色的
4.任意一个节点到每一个叶子节点的路径都有相同数目的黑色节点(任意节点不好理解,理解成根节点就好了)
备注:看完定义可能会一脸蒙圈,如果已经熟悉了二叉查找树,那根据定义去构建一颗红黑树,你就会发现着色的奥妙。只要你根据它的定义去插入,会得到一颗趋向完美分布的查找二叉树。
红黑树的插入:
根据定义去构建红黑树,如果没有方法,会发现这到底要怎么插入才能满足红黑树的定义。
对于插入,这篇文章的方法完全可行 https://www.jianshu.com/p/e136ec79235c
它将方法概况成了以下:
红黑树的删除:
如果上面的插入已经觉的复杂,那么它的删除就更复杂了。删除之后,如何确保它依然是一颗红黑树,方法也是相当难。
这篇文章的删除方法大纲上是没有错误的,只有一些极端情况还需要自己额外处理一下。https://blog.youkuaiyun.com/spch2008/article/details/9338923
实现红黑树:
这是我用java实现了红黑树
package com.tczs.tree;
import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.Stack;
/**
* 红黑树
* @author tao.li
* @date 2020.10.14
*/
public class RedBlackTree<T extends Comparable<T>> {
private TreeNode<T> root;
private int length;
private int index;
public RedBlackTree(){
this.root = null;
}
public RedBlackTree(T element){
checkNull(element);
this.root = new TreeNode<>(element,false,null,false,null,null);
}
public int size(){
return this.length;
}
/**
* 将树中的元素按以小到大的顺序收入数组中并返回
* @return
*/
public T[] toArray(){
if(root == null)
return null;
T[] array = initArray();
array = traverse(this.root, array);
this.index = 0;
return array;
}
private T[] traverse(TreeNode<T> root,T[] array){
if(root != null){
array = traverse(root.left,array);
array[this.index++] = root.element;
array = traverse(root.right,array);
}
return array;
}
/**
* 查询最小元素
* @return
*/
public T finMin(){
return finMin(this.root);
}
private T finMin(TreeNode<T> root){
if(root.left == null){
return root.element;
}else{
return finMin(root.left);
}
}
public void lookTreeConstruct(){
lookTreeConstruct(this.root);
}
private void lookTreeConstruct(TreeNode<T> root){
if(root != null){
ModelDemo demo = (ModelDemo) root.element;
System.out.print("当前节点元素:"+demo.getValue()+" 颜色 "+root.isRed+" ");
if(root.left != null){
ModelDemo left = (ModelDemo) root.left.element;
System.out.print("左节点元素:"+left.getValue()+" ");
}else {
System.out.print("左节点元素:"+" ");
}
if(root.right != null){
ModelDemo right = (ModelDemo) root.right.element;
System.out.print("右节点元素:"+right.getValue()+" ");
}else {
System.out.print("右节点元素:"+" ");
}
if(root.header != null){
ModelDemo father = (ModelDemo) root.header.element;
System.out.print("父节点元素:"+father.getValue()+" "+"在左边 "+root.isLeft);
}else {
System.out.print("父节点元素:"+" ");
}
System.out.println();
lookTreeConstruct(root.left);
lookTreeConstruct(root.right);
}
}
/**
* 查询最大元素
* @return
*/
public T finMax(){
return finMax(this.root);
}
private T finMax(TreeNode<T> root){
if(root.right == null){
return root.element;
}else{
return finMax(root.right);
}
}
private T[] initArray(){
TreeNode<T> root = this.root;
if(root == null){
throw new NullPointerException("root is null");
}else {
return (T[]) Array.newInstance(root.element.getClass(),this.length);
}
}
/**
* 前序遍历
* @return
*/
public Iterator<T> Iterator(){
return new Itr<T>();
}
public void insert(T element){
checkNull(element);
TreeNode<T> root = this.root;
if(root == null){
this.root = new TreeNode<>(element,false,null,false,null,null);
this.length++;
}else {
TreeNode<T> location = findLocation(element, root);
if (location != null) {
boolean isLeftParent = true;
if (location.element.compareTo(element) > 0) {
location.left = new TreeNode<>(element, true, location,true, null, null);
} else {
isLeftParent = false;
location.right = new TreeNode<>(element, true, location, false,null, null);
}
insertUpdateTree(location, isLeftParent);
this.length++;
}
}
}
/**
* @param root 当前节点(插入节点 < 当前节点 < 父节点)
*/
private void insertUpdateTree(TreeNode<T> root,boolean isLeftParent){
if(root.isRed) {
TreeNode<T> parent = root.header;
TreeNode<T> uncle;
if (root.isLeft)
uncle = parent.right;
else
uncle = parent.left;
if (uncle != null && uncle.isRed) {
uncle.isRed = false;
root.isRed = false;
parent.isRed = true;
if(parent.header != null){
insertUpdateTree(parent.header,parent.isLeft);
}else{
parent.isRed = false;
}
} else {
if (root.isLeft) {
if (isLeftParent) {
root.isRed = false;
parent.isRed = true;
rotateRight(root);
}else {
rotateLeft(root);
insertUpdateTree(parent.left,true);
}
}else{
if(isLeftParent){
rotateRight(root.left);
insertUpdateTree(root.header,false);
}else{
root.isRed = false;
parent.isRed = true;
rotateLeft(root.header);
}
}
}
}
}
public void remove(T element){
if(element == null)
return;
TreeNode<T> target = contains(element,this.root);
if(target != null){
remove(target);
}
}
private void remove(TreeNode<T> target){
if(length == 1) { //只剩跟节点
helpGc(target);
this.root = null;
}else if(target.left == null && target.right != null
&& target.right.left == null && target.right.right == null){ //目标节点是单节点直接替换
TreeNode<T> replace = target.right;
target.element = replace.element;
target.right = null;
helpGc(replace);
}else if(target.right == null && target.left != null
&& target.left.left == null && target.left.right == null){ //目标节点是单节点直接替换
TreeNode<T> replace = target.left;
target.element = replace.element;
target.left = null;
helpGc(replace);
}else if(target.left == null && target.right == null){ //目标节点无子节点
if(target.isRed){ //目标节点是红色直接删除
TreeNode<T> parent = target.header;
if(target.isLeft)
parent.left = null;
else
parent.right = null;
helpGc(target);
}else{ //目标节点是黑色先调整树结构再删除
removeUpdateTree(target);
TreeNode<T> parent = target.header;
if(target.isLeft)
parent.left = null;
else
parent.right = null;
helpGc(target);
}
}else{ //目标节点左右节点都存在或者(只含有左节点或右节点,但长度大于1)
if(target.right == null){ //右节点不存在我们使用前继节点作为替换
targetRightisNull(target);
return;
}
//下面情形: 右节点存在或者左右节点都存在使用后继节点替换
TreeNode<T> replace = getReplace(target.right);
target.element = replace.element;
if(replace.right != null){ //替换节点存在右节点(如果有子节点必然只有右节点)
TreeNode<T> replaceRight = replace.right;
TreeNode<T> replaceParent = replace.header;
replaceRight.header = replaceParent;
replaceRight.isLeft = replace.isLeft;
if(!replace.isRed)
replaceRight.isRed = false;
if(replace.isLeft)
replaceParent.left = replaceRight;
else
replaceParent.right = replaceRight;
helpGc(replace);
}else if(replace.isRed){ //替换节点是红节点,直接删除
TreeNode<T> parent = replace.header;
if(replace.isLeft)
parent.left = null;
else
parent.right = null;
helpGc(replace);
}else{
removeUpdateTree(replace);
TreeNode<T> parent = replace.header;
if(replace.isLeft)
parent.left = null;
else
parent.right = null;
helpGc(replace);
}
}
}
private void removeUpdateTree(TreeNode<T> delete){
TreeNode<T> parent = delete.header;
TreeNode<T> brother;
if(delete.isLeft)
brother = parent.right;
else
brother = parent.left;
if(brother == null)
return;
if(brother.isRed){
if(parent.isRed)
parent.isRed = false;
else
parent.isRed = true;
if(brother.isRed)
brother.isRed = false;
else
brother.isRed = true;
if(brother.isLeft)
rotateRight(brother);
else
rotateLeft(parent);
removeUpdateTree(delete);
}else{
TreeNode<T> brotherLeft = brother.left;
TreeNode<T> brotherRight = brother.right;
if((brotherLeft == null && brotherRight == null) ||
(brotherLeft != null && !brotherLeft.isRed && brotherRight != null && !brotherRight.isRed)){
brother.isRed = true;
if(parent.isRed)
parent.isRed = false;
else if(parent.header != null)
removeUpdateTree(parent);
}
if(brotherLeft != null && brotherLeft.isRed && (brotherRight == null || !brotherRight.isRed)){
brotherLeft.isRed = false;
brother.isRed = true;
rotateRight(brotherLeft);
removeUpdateTree(delete);
}
if(brotherRight != null && brotherRight.isRed){
brother.isRed = parent.isRed;
parent.isRed = false;
if(brother.isLeft) {
rotateRight(brother);
if(brotherLeft != null)
brotherLeft.isRed = false;
}
else {
rotateLeft(parent);
brotherRight.isRed = false;
}
}
}
}
private void helpGc(TreeNode<T> node){
node.header = null;
node.element = null;
node.left = null;
node.right = null;
this.length--;
}
private TreeNode<T> getReplace(TreeNode<T> target){
if(target.left == null)
return target;
return getReplace(target.left);
}
/**
* 目标节点的右节点不存在我们使用前继节点作为替换
* @param target
*/
private void targetRightisNull(TreeNode<T> target){
TreeNode<T> replace = target.left;
TreeNode<T> replaceRight = replace.right;
while(replaceRight != null){
replace = replaceRight;
replaceRight = replaceRight.right;
}
target.element = replace.element;
if(replace.left == null){
removeUpdateTree(replace);
TreeNode<T> replaceParent = replace.header;
if(replace.isLeft)
replaceParent.left = null;
else
replaceParent.right = null;
}else {
TreeNode<T> replaceLeft = replace.left;
TreeNode<T> replaceParent = replace.header;
replaceLeft.header = replaceParent;
replaceLeft.isLeft = replace.isLeft;
if(replace.isLeft)
replaceParent.left = replaceLeft;
else
replaceParent.right = replaceLeft;
}
helpGc(replace);
}
private void removeObject(Object element){
remove((T) element);
}
private TreeNode<T> contains(T element,TreeNode<T> root){
if(root == null)
return null;
T old = root.element;
if(old.compareTo(element) > 0)
return contains(element,root.left);
else if(old.compareTo(element) < 0)
return contains(element,root.right);
else
return root;
}
/**
* 向右旋转(对父节点右旋)
* @param root 当前节点(插入节点 < 当前节点 < 父节点)
*/
private void rotateRight(TreeNode<T> root){
TreeNode<T> parent = root.header;
TreeNode<T> grandParent = parent.header;
TreeNode<T> rootRight = root.right;
if(rootRight != null){
rootRight.header = parent;
rootRight.isLeft = true;
}
root.right = parent;
root.header = grandParent;
parent.left = rootRight;
parent.header = root;
if(grandParent == null) {
this.root = root;
}else if(parent.isLeft) {
grandParent.left = root;
root.isLeft = true;
}else {
grandParent.right = root;
root.isLeft = false;
}
parent.isLeft = false;
}
/**
* 向左旋转(对当前节点左旋)
* @param root 当前节点(插入节点 < 当前节点 < 父节点)
*/
private void rotateLeft(TreeNode<T> root){
TreeNode<T> parent = root.header;
TreeNode<T> subNode = root.right;
TreeNode<T> subLeft = subNode.left;
if(subLeft != null){
subLeft.header = root;
subLeft.isLeft = false;
}
subNode.left = root;
root.right = subLeft;
subNode.header = parent;
root.header = subNode;
if(parent == null) {
this.root = subNode;
}else if(root.isLeft) {
parent.left = subNode;
subNode.isLeft = true;
}else {
parent.right = subNode;
subNode.isLeft = false;
}
root.isLeft = true;
}
private TreeNode<T> findLocation(T element,TreeNode<T> root){
T old = root.element;
if(old.compareTo(element) > 0){
// this.isLeftGrandParent = true;
if(root.left == null)
return root;
else
return findLocation(element,root.left);
}else if(old.compareTo(element) < 0){
if(root.right == null)
return root;
else
return findLocation(element,root.right);
}else
root.element = element;
return null;
}
private void checkNull(T element){
if(element == null)
throw new NullPointerException("element is null");
}
class Itr<T> implements Iterator<T>{
private int modCount;
private int exceptLength;
private RedBlackTree.TreeNode currentNode;
Stack<RedBlackTree.TreeNode> remainNodes = new Stack<>();
Itr(){
this.modCount = RedBlackTree.this.length;
this.exceptLength = RedBlackTree.this.length;
this.currentNode = RedBlackTree.this.root;
}
@Override
public boolean hasNext() {
return exceptLength > 0;
}
@Override
public T next() {
checkLength();
T element = (T) currentNode.element;
if(currentNode.right != null)
remainNodes.push(currentNode.right);
if(currentNode.left == null) {
if(remainNodes.size() > 0) {
currentNode = remainNodes.pop();
}
}else
currentNode = currentNode.left;
exceptLength--;
return element;
}
private void checkLength(){
if(modCount != RedBlackTree.this.length)
throw new IllegalArgumentException("status is error");
}
}
class TreeNode<T>{
T element;
boolean isRed;
TreeNode<T> header;
boolean isLeft;
TreeNode<T> left;
TreeNode<T> right;
public TreeNode(T element, boolean isRed, TreeNode<T> header,boolean isLeft, TreeNode<T> left, TreeNode<T> right) {
this.element = element;
this.isRed = isRed;
this.header = header;
this.isLeft = isLeft;
this.left = left;
this.right = right;
}
}
}
展望:
对于红黑树的迭代器,我实现了用前序遍历来迭代。我实现了hasNext()方法和next()方法,对于遍历结果是没有问题的,但是要重写迭代器的remove()方法遇到了困难。因为遍历是根据树的结构用前序遍历来执行的,而删除节点会破坏树的结构,树的结构发生变化,导致前后冲突。所以如何重写它的remove()方法呢?