手写数据结构之红黑树

红黑树的作用:

前面我写了一个普通查找二叉树,普通查找二叉树有一个弊端,就是可能会有极坏的情况(节点一边倒,分布不完全)。那么红黑树就是一种特殊的查找二叉树,能让节点尽可能完全分布的情况。

红黑树的定义:

红黑树是具有以下着色性质的二叉查找树:

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()方法呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

3wtczs93点抗母

钱癌晚期

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值