紅黑樹

1、紅黑樹原理

一、紅黑樹的insert(新的插入的節點默認爲紅色)

  (1)若是插入是根節點,直接把節點塗爲黑色,把節點設置爲根節點html

  (2)若是插入的節點的父節點是黑色,無需任何處理java

  (3)須要修復的狀況ide

    狀況1:當前節點的父節點爲紅色,叔叔節點爲紅色,解決辦法:(將當前節點的父節點和叔叔節點塗黑,祖父節點塗紅,把當前節點指向祖父節點,從新開始遞歸調整),根節點塗黑this

    狀況2:當前節點的父節點爲紅色,叔叔節點爲null或者黑色(或者的狀況雖然在當前不存在,可是在狀況1的遞歸條件下是存在的),當前節點爲父節點的右孩子,解決辦法:須要先左旋,(左旋後,把父節點當成當前節點,當前節點的父節點塗黑,祖父節點塗紅,後右旋),根節點塗黑(父節點爲祖父左孩子的狀況)spa

    狀況3:當前節點的父節點爲紅色,叔叔節點爲null或者黑色(或者的狀況雖然在當前不存在,可是在狀況1的遞歸條件下是存在的),當前節點爲父節點的左孩子,解決辦法:父節點塗黑,祖父節點塗紅,直接右旋,根節點塗黑(父節點爲祖父左孩子的狀況).net

二、紅黑樹的刪除

  (1)刪除紅色的葉子節點,直接刪除code

  (2)刪除的紅色節點有左子樹或者右子樹的狀況,這種狀況不存在orm

  (3)刪除黑色的葉子結點htm

    狀況1:兄弟節點爲紅色,那父節點就必須爲黑色,解決方法:把兄弟節點和父節點顏色對調,而後左旋,就變成了狀況2,或者狀況3blog

    狀況2:兄弟節點爲黑色節點,遠侄子節點爲紅色,解決辦法:把兄弟節點與父節點顏色對調,而後左旋,把侄子節點顏色變黑,刪除目的節點

    狀況3:兄弟節點爲黑色節點,近侄子節點爲紅色,解決辦法:把近侄子節點和該侄子的父節點進行右旋,而後他兩顏色互換,而後就變成了狀況2

    狀況4:兄弟節點爲黑色,侄子節點也爲黑色,這種狀況不存在(但,這種狀況在狀況6的遞歸狀況中是存在的,因此也得考慮)

    狀況5:兄弟節點爲黑色,無侄子節點,父節點爲紅色,解決辦法:把父節點變成黑色,兄弟節點變成紅色,刪除目的節點

    狀況6:兄弟節點爲黑色,無侄子節點,父節點爲黑色,解決辦法:把兄弟節點變成紅色,刪除目的節點,接着把當前節點指向父節點,而後按照父節點爲黑色葉子節點的狀況進行遞歸調整

  (4)刪除的黑色節點有左子樹或者右子樹的狀況,固然這個時候它的左子樹或者右子樹節點只能是紅色不能是黑色,處理方法簡單:即用黑色節點的孩子替換黑色節點,並將替換後的節點染成黑色。

三、紅黑樹三旋轉(insert一旋轉,delete二旋轉)

其中,insert一旋轉,向插入節點子樹的對立方向旋轉(以祖父爲中心)( 祖父節點和父節點顏色互換)

delete的二旋轉,兩次都是向刪除節點的同一方向旋轉(兩次都是以父親爲中心)(第一次旋轉:父節點和兄弟節點顏色互換)(第二次旋轉:父節點和兄弟節點顏色互換,侄子節點塗黑)

2、二叉排序樹中須要旋轉的場景描述(旋轉須要有三個點,固然第三個點也能夠是null)

左旋或者右旋的三要素:

一、包含根節點的變動

二、除根節點外,包含三個點的操做

三、

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

       http://www.javashuo.com/article/p-prpqbtus-ek.html

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

相關文章
相關標籤/搜索