zoukankan      html  css  js  c++  java
  • 红黑树

    一、红黑树原理

    1、红黑树的insert(新的插入的节点默认为红色)

      (1)如果插入是根节点,直接把节点涂为黑色,把节点设置为根节点

      (2)如果插入的节点的父节点是黑色,无需任何处理

      (3)需要修复的情况

        情况1:当前节点的父节点为红色,叔叔节点为红色,解决办法:(将当前节点的父节点和叔叔节点涂黑,祖父节点涂红,把当前节点指向祖父节点,重新开始递归调整),根节点涂黑

        情况2:当前节点的父节点为红色,叔叔节点为null或者黑色(或者的情况虽然在当前不存在,但是在情况1的递归条件下是存在的),当前节点为父节点的右孩子,解决办法:需要先左旋,(左旋后,把父节点当成当前节点,当前节点的父节点涂黑,祖父节点涂红,后右旋),根节点涂黑(父节点为祖父左孩子的情况)

        情况3:当前节点的父节点为红色,叔叔节点为null或者黑色(或者的情况虽然在当前不存在,但是在情况1的递归条件下是存在的),当前节点为父节点的左孩子,解决办法:父节点涂黑,祖父节点涂红,直接右旋,根节点涂黑(父节点为祖父左孩子的情况)

    2、红黑树的删除

      (1)删除红色的叶子节点,直接删除

      (2)删除的红色节点有左子树或者右子树的情况,这种情况不存在

      (3)删除黑色的叶子结点

        情况1:兄弟节点为红色,那父节点就必须为黑色,解决方法:把兄弟节点和父节点颜色对调,然后左旋,就变成了情况2,或者情况3

        情况2:兄弟节点为黑色节点,远侄子节点为红色,解决办法:把兄弟节点与父节点颜色对调,然后左旋,把侄子节点颜色变黑,删除目的节点

        情况3:兄弟节点为黑色节点,近侄子节点为红色,解决办法:把近侄子节点和该侄子的父节点进行右旋,然后他两颜色互换,然后就变成了情况2

        情况4:兄弟节点为黑色,侄子节点也为黑色,这种情况不存在(但,这种情况在情况6的递归情况中是存在的,所以也得考虑)

        情况5:兄弟节点为黑色,无侄子节点,父节点为红色,解决办法:把父节点变成黑色,兄弟节点变成红色,删除目的节点

        情况6:兄弟节点为黑色,无侄子节点,父节点为黑色,解决办法:把兄弟节点变成红色,删除目的节点,接着把当前节点指向父节点,然后按照父节点为黑色叶子节点的情况进行递归调整

      (4)删除的黑色节点有左子树或者右子树的情况,当然这个时候它的左子树或者右子树节点只能是红色不能是黑色,处理方法简单:即用黑色节点的孩子替换黑色节点,并将替换后的节点染成黑色。

    3、红黑树三旋转(insert一旋转,delete二旋转)

    其中,insert一旋转,向插入节点子树的对立方向旋转(以祖父为中心)( 祖父节点和父节点颜色互换)

    delete的二旋转,两次都是向删除节点的同一方向旋转(两次都是以父亲为中心)(第一次旋转:父节点和兄弟节点颜色互换)(第二次旋转:父节点和兄弟节点颜色互换,侄子节点涂黑)

    二、二叉排序树中需要旋转的场景描述(旋转需要有三个点,当然第三个点也可以是null)

    左旋或者右旋的三要素:

    1、包含根节点的变更

    2、除根节点外,包含三个点的操作

    3、

    三、红黑树的代码

    package main;
    
    import java.util.LinkedList;
    import java.util.Queue;
    
    public class RBTree<T extends Comparable<T>> {
        private static final boolean RED = false;
        private static final boolean BLACK = true;
        private RBNode<T> root = null;
        public class RBNode<T>{
            private T key;
            private boolean color;
            private RBNode<T> parent;
            private RBNode<T> left;
            private RBNode<T> right;
            public RBNode(T key) {
                this.key = key;
                this.color = RED;
                this.parent = null;
                this.left = null;
                this.right = null;
            }
        }
        public static void main(String[] args) {
            RBTree<Integer> rbree = new RBTree<>();
            rbree.insert(1);
            rbree.insert(9);
            rbree.insert(5);
            rbree.insert(8);
            rbree.insert(2);
            rbree.insert(4);
            rbree.insert(7);
            rbree.insert(6);
            rbree.insert(3);
            rbree.insert(10);
            rbree.insert(11);
            rbree.insert(12);
            rbree.delete(5);
            rbree.delete(4);
            rbree.delete(10);
            rbree.delete(9);
            rbree.show();
        }
        //红黑树的展示
        public void show() {
            int h = height(this.root);
            Queue<RBNode<T>> queue = new LinkedList<>();
            queue.add(this.root);
            RBNode<T> tempNode = null;
            for(int i=1;i<=h;++i) {
                for(int j=0;j<Math.pow(2, h-i)-1;++j) {
                    System.out.print("    ");
                }
                for(int j=0;j<Math.pow(2, i-1);++j) {
                    tempNode = queue.remove();
                    if(tempNode==null) {
                        System.out.print("__");
                        System.out.print(":W");
                        queue.add(null);
                        queue.add(null);
                    }else {
                        System.out.print(String.format("%2d", tempNode.key));
                        System.out.print(':');
                        System.out.print(tempNode.color?'B':'R');
                        queue.add(tempNode.left);
                        queue.add(tempNode.right);
                    }
                    for(int k=0;k<Math.pow(2, h-i+1)-1;++k) {
                        System.out.print("    ");
                    }
                }
                System.out.println();
            }
        }
        //红黑树的高度
        public int height(RBNode<T> rootNode) {
            if(rootNode==null) {
                return 0;
            }else {
                return height(rootNode.left)>height(rootNode.right)?(height(rootNode.left)+1):(height(rootNode.right)+1);
            }
        }
        //节点的插入
        public void insert(T key) {
            RBNode<T> newNode = new RBNode<>(key);
            RBNode<T> tempNode = this.root;
            RBNode<T> preNode = this.root;
            while(tempNode!=null) {
                preNode = tempNode;
                if(tempNode.key.compareTo(key)==0) {
                    return;
                }else if(tempNode.key.compareTo(key)<0){
                    tempNode = tempNode.right;
                }else {
                    tempNode = tempNode.left;
                }
            }
            if(preNode==null) {
                this.root = newNode;
            }else if(preNode.key.compareTo(key)<0) {
                preNode.right = newNode;
                newNode.parent = preNode;
            }else{
                preNode.left = newNode;
                newNode.parent = preNode;
            }
            //节点插入后需要进行颜色和位置的调整
            fixupInsert(newNode);
        }
        //节点插入的调整
        public void fixupInsert(RBNode<T> newNode) {
            if(newNode.parent==null||newNode.parent.color == BLACK) {
                //父节点没有或者父节点为黑色时不做任何处理
            }else {
                //父节点
                RBNode<T> parentNode = newNode.parent;
                //祖父节点
                RBNode<T> grandParentNode = parentNode.parent;
                //叔叔节点
                RBNode<T> uncleNode = null;
                if(grandParentNode.left==parentNode) {
                    uncleNode = grandParentNode.right;
                }else {
                    uncleNode = grandParentNode.left;
                }
                //叔叔节点为黑色(这里的条件在递归中作用很大)
                if(uncleNode==null||uncleNode.color) {
                    if(grandParentNode.left==parentNode&&parentNode.left==newNode) {
                        parentNode.color = BLACK;
                        grandParentNode.color = RED;
                        rightRotate(grandParentNode);
                    }else if(grandParentNode.left==parentNode&&parentNode.right==newNode){
                        leftRotate(parentNode);
                        newNode.color = BLACK;
                        grandParentNode.color = RED;
                        rightRotate(grandParentNode);
                    }else if(grandParentNode.right==parentNode&&parentNode.left==newNode){
                        rightRotate(parentNode);
                        newNode.color = BLACK;
                        grandParentNode.color = RED;
                        leftRotate(grandParentNode);
                    }else {
                        parentNode.color = BLACK;
                        grandParentNode.color = RED;
                        leftRotate(grandParentNode);
                    }
                }else {//叔叔节点位红色
                    parentNode.color = BLACK;
                    uncleNode.color = BLACK;
                    grandParentNode.color = RED;
                    fixupInsert(grandParentNode);
                }
            }
            this.root.color = BLACK;//根节点设为黑色
        }
        public void delete(T key) {
            RBNode<T> tempNode = this.root;
            RBNode<T> tempLeftNode = null;
            //寻找删除的节点
            while(tempNode!=null) {
                if(tempNode.key.compareTo(key)==0) {
                    if(tempNode.left!=null&&tempNode.right!=null) {
                        tempLeftNode = tempNode.left;
                        while(tempLeftNode.right!=null) {
                            tempLeftNode = tempLeftNode.right;
                        }
                        tempNode.key = tempLeftNode.key;
                        tempNode = tempLeftNode;
                    }
                    break;
                }else if(tempNode.key.compareTo(key)<0) {
                    tempNode = tempNode.right;
                }else {
                    tempNode = tempNode.left;
                }
            }
            //需要删除的节点为tempNode
            if(tempNode!=null) {
                if(tempNode.left!=null) {//删除节点有红色的左孩子节点
                    tempNode.left.color = BLACK;
                    if(tempNode.parent==null) {
                        this.root = tempNode.left;
                        tempNode.left.parent = null;
                    }else {
                        if(tempNode.parent.left==tempNode) {
                            tempNode.parent.left = tempNode.left;
                            tempNode.left.parent = tempNode.parent;
                        }else {
                            tempNode.parent.right = tempNode.left;
                            tempNode.left.parent = tempNode.parent;
                        }
                    }
                }else if(tempNode.right!=null) {//删除节点有红色的右孩子节点
                    tempNode.right.color = BLACK;
                    if(tempNode.parent==null) {
                        this.root = tempNode.right;
                        tempNode.right.parent = null;
                    }else {
                        if(tempNode.parent.left==tempNode) {
                            tempNode.parent.left = tempNode.right;
                            tempNode.right.parent = tempNode.parent;
                        }else {
                            tempNode.parent.right = tempNode.right;
                            tempNode.right.parent = tempNode.parent;
                        }
                    }
                }else if(!tempNode.color){//删除红色叶子结点
                    if(tempNode.parent==null) {
                        this.root = null;
                    }else {
                        if(tempNode.parent.left==tempNode) {
                            tempNode.parent.left = null;
                        }else {
                            tempNode.parent.right = null;
                        }
                    }
                }else {//删除黑色叶子结点
                    fixupDelete(tempNode);//先调整,后删除
                    if(tempNode.parent==null) {
                        this.root = null;
                    }else {
                        if(tempNode.parent.left==tempNode) {
                            tempNode.parent.left = null;
                        }else {
                            tempNode.parent.right = null;
                        }
                    }
                }
            }
        }
        public void fixupDelete(RBNode<T> tempNode) {
            RBNode<T> parentNode = null;
            if(tempNode.parent==null) {
                return;
            }else {
                parentNode = tempNode.parent;
            }
            RBNode<T> uncleNode = null;
            if(parentNode.left==tempNode) {
                uncleNode = parentNode.right;
            }else {
                uncleNode = parentNode.left;
            }
            //删除节点的兄弟节点为红色的情况
            if(parentNode.color==BLACK&&uncleNode.color==RED) {
                parentNode.color = RED;
                uncleNode.color = BLACK;
                if(parentNode.left==uncleNode) {
                    rightRotate(parentNode);
                }else {
                    leftRotate(parentNode);
                }
                if(parentNode.left==tempNode) {
                    uncleNode = parentNode.right;
                }else {
                    uncleNode = parentNode.left;
                }
            }
            //删除节点的兄弟节点为黑色的情况
            if(parentNode.right==uncleNode) {
                if(uncleNode.right!=null&&!uncleNode.right.color) {//远侄子节点为红色
                    uncleNode.color = parentNode.color;
                    parentNode.color = BLACK;
                    uncleNode.right.color = BLACK;
                    leftRotate(parentNode);
                }else if(uncleNode.left!=null&&!uncleNode.left.color){//近侄子节点为红色
                    uncleNode.left.color = parentNode.color;
                    parentNode.color = BLACK;
                    rightRotate(uncleNode);
                    leftRotate(parentNode);
                }else if(parentNode.color) {//父节点为黑色,两个侄子节点为null或者在低轨情况下可能都为黑色
                    uncleNode.color = RED;
                    fixupDelete(parentNode);
                }else {//父节点为红色,两个侄子节点为null或者在低轨情况下可能都为黑色
                    uncleNode.color = RED;
                    parentNode.color = BLACK;
                }
            }else {
                if(uncleNode.left!=null&&!uncleNode.left.color) {//远侄子节点为红色
                    uncleNode.color = parentNode.color;
                    parentNode.color = BLACK;
                    uncleNode.left.color = BLACK;
                    rightRotate(parentNode);
                }else if(uncleNode.right!=null&&!uncleNode.right.color) {//近侄子节点为红色
                    uncleNode.right.color = parentNode.color;
                    parentNode.color= BLACK;
                    leftRotate(uncleNode);
                    rightRotate(parentNode);
                }else if(parentNode.color) {//父节点为黑色,两个侄子节点为null或者在低轨情况下可能都为黑色
                    uncleNode.color = RED;
                    fixupDelete(parentNode);
                }else {//父节点为红色,两个侄子节点为null或者在低轨情况下可能都为黑色
                    uncleNode.color = RED;
                    parentNode.color = BLACK;
                }
            }
            this.root.color = BLACK;
            
        }
        //以参数节点为中心进行左旋
        public void leftRotate(RBNode<T> rotateNode) {
            RBNode<T> rightNode = rotateNode.right;
            //对承接节点的处理
            if(rotateNode.parent==null) {
                rightNode.parent = null;
                this.root = rightNode;
            }else {
                rightNode.parent = rotateNode.parent;
                if(rotateNode.parent.left==rotateNode) {
                    rotateNode.parent.left = rightNode;
                }else {
                    rotateNode.parent.right = rightNode;
                }
            }
            //对支节点的处理
            rotateNode.right = rightNode.left;
            if(rightNode.left!=null) {
                rightNode.left.parent = rotateNode;    
            }    
            //对当下节点的处理
            rightNode.left = rotateNode;
            rotateNode.parent = rightNode;
        }
        //以参数节点为中心进行右旋
        public void rightRotate(RBNode<T> rotateNode) {
            RBNode<T> leftNode = rotateNode.left;
            //对承接节点的处理
            if(rotateNode.parent==null) {
                leftNode.parent = null;
                this.root = leftNode;
            }else {
                leftNode.parent = rotateNode.parent;
                if(rotateNode.parent.left==rotateNode) {
                    rotateNode.parent.left = leftNode;
                }else {
                    rotateNode.parent.right = leftNode;
                }
            }
            //对支节点的处理
            rotateNode.left = leftNode.right;
            if(leftNode.right!=null) {
                leftNode.right.parent = rotateNode;
            }
            //对当下节点的处理
            leftNode.right = rotateNode;
            rotateNode.parent = leftNode;
        }
    }

    参考文献

    红黑树的理解:https://blog.csdn.net/li2327234939/article/details/75628448

           https://baijiahao.baidu.com/s?id=1623524026892185878&wfr=spider&for=pc

           https://www.cnblogs.com/xuxinstyle/p/9556998.html

           https://www.cnblogs.com/zedosu/p/6635034.html

           https://www.cnblogs.com/qingergege/p/7351659.html

              https://blog.csdn.net/qq_34173549/article/details/79636764

  • 相关阅读:
    Windows Server 2003 R2 IIS服务的命令行方式重启命令
    DWZ学习记录--关闭loading效果
    td顶部对齐
    struts2 iterator 迭代标签只显示前五条记录
    struts2 select 默认选中
    struts2 select标签
    s:select 标签中list存放map对象的使用
    struts2中<s:select>标签的使用
    eclipse在Windows7 64 位下出现Unhandled event loop exception No more handles
    Jquery焦点图/幻灯片效果 插件 KinSlideshow
  • 原文地址:https://www.cnblogs.com/erdanyang/p/11422790.html
Copyright © 2011-2022 走看看