0    课程地址

https://coding.imooc.com/lesson/207.html#mid=15185

 

1    重点关注

1.1    红黑树本节解析草图

  • 2节点添加节点:

如下图(其实有4种情况):

A  黑Node 左侧 添加 红Node,      正常

B  黑Node 右侧 添加 红Node,  右节点 为红,左节点为黑, 左旋转,形成A的情况

C       红Node 右侧 添加 红Node,      左旋转,   形成红Node 左侧挂红Node的情况,这个在下图2.B可以解决

D  红Node 左侧 添加 红Node,      如下图1.C情况,在2.B可以解决

 

3节点添加节点

A  父Node 右侧  添加 红Node,  形成了4节点,颜色翻转,4节点拆分,父节点向上融合

B  子Node 左侧  添加 红Node,  父节点右旋转,再颜色翻转,4节点拆分,父节点向上融合

C  子Node 右侧  添加 红Node,  子节点左旋转,父节点右旋转,再颜色翻转,4节点拆分,父节点向上融合

关于为什么4节点不会出现父节点是红色的情况,首先,如果父节点为根节点,只能是黑。往下推,只有2中的三种情况,结果都是子节点为黑,父节点为红(如果父节点为根节点4置黑了)

 

 

 

 

2    课程内容

 

 

3    Coding

3.1    红黑树Coding

关键代码:

 

        if(isRed(node.right)&&!isRed(node.left)){
            node = leftRotate(node);
        }
        if(isRed(node.left)&&isRed(node.left.left)){
            node = rightRotate(node);
        }
        if(isRed(node.left)&&isRed(node.right)){
            flipColors(node);
        }

 

 

红黑树类:

package com.company;

import java.util.ArrayList;
import java.util.List;

public class RBTree<K extends Comparable<K>,V> {
    private static final boolean RED = true;
    private static final boolean BLACK = false;

    //1     定义Node
    class Node{
        private K key;
        private V value;
        private Node left,right;
        private int height;
        private boolean color;

        public Node(K key, V value){
            this.key = key;
            this.value = value;
            this.left = null;
            this.right = null;
            this.height = 1;
            this.color = RED;
        }

        @Override
        public String toString() {
            final StringBuffer sb = new StringBuffer("Node{");
            sb.append("key=").append(key);
            sb.append(", value=").append(value);
            sb.append('}');
            return sb.toString();
        }
    }

    //2     定义属性
    private int size;
    private Node root;

    /**
     * 获取节点颜色
     * @author weidoudou
     * @date 2023/4/21 20:35
     * @param node 请添加参数描述
     * @return boolean
     **/
    private boolean isRed(Node node){
        if(node == null){
            return BLACK;
        }
        return node.color;
    }


    /**
     * 无参构造函数
     * @author weidoudou
     * @date 2023/1/1 11:09
     * @return null
     **/
    public RBTree(){
        this.size = 0;
        this.root = null;
    }



    public boolean isEmpty() {
        return size==0?true:false;
    }

    public int getSize() {
        return size;
    }

    //3     定义包含函数
    private Node containsKey(K key,Node node){
        //结束条件
        if(null==node){
            return null;
        }

        //循环条件
        if(key.compareTo(node.key)<0){
            return containsKey(key,node.left);
        }else if(key.compareTo(node.key)>0){
            return containsKey(key, node.right);
        }else{//key.compareTo(node.key)=0 其实这个也是结束条件
            return node;
        }
    }

    public boolean contains(K key) {
        return containsKey(key,root)==null?false:true;
    }

    public V get(K key) {
        Node node = containsKey(key,root);
        if(null!=node){
            return node.value;
        }
        return null;
    }


    //3     递归,添加元素
    public Node add(K key,V value,Node node){
        if(node == null){
            size ++;
            return new Node(key, value); // 默认插入红色节点
        }

        if(key.compareTo(node.key) < 0)
            node.left = add(key, value,node.left);
        else if(key.compareTo(node.key) > 0)
            node.right = add(key, value,node.right);
        else // key.compareTo(node.key) == 0
            node.value = value;


        if(isRed(node.right)&&!isRed(node.left)){
            node = leftRotate(node);
        }
        if(isRed(node.left)&&isRed(node.left.left)){
            node = rightRotate(node);
        }
        if(isRed(node.left)&&isRed(node.right)){
            flipColors(node);
        }

        return node;
    }

    /**
     * 颜色翻转
     * @author weidoudou
     * @date 2023/5/6 6:37
     * @param node 请添加参数描述
     * @return void
     **/
    private void flipColors(Node node){
        node.left.color = BLACK;
        node.right.color = BLACK;
        node.color = RED;
    }

    //   node                     x
    //  /   \     左旋转         /  \
    // T1   x   --------->   node   T3
    //     / \              /   \
    //    T2 T3            T1   T2
    private Node leftRotate(Node node) {
        Node x = node.right;
        Node T2 = x.left;

        // 向左旋转过程
        node.right = T2;
        x.left = node;

        // 更新color
        x.color = node.color;
        node.color = RED;

        return x;
    }

    //     node                   x
    //    /   \     右旋转       /  \
    //   x    T2   ------->   y   node
    //  / \                       /  \
    // y  T1                     T1  T2
    private Node rightRotate(Node node){

        Node x = node.left;
        node.left = x.right;
        x.right = node;

        x.color = node.color;
        node.color = RED;
        return x;
    }

    /**
     * 添加节点后根节点设置为黑色
     * @author weidoudou
     * @date 2023/5/5 7:01
     * @param key 请添加参数描述
     * @param  value 请添加参数描述
     * @return void
     **/
    public void add(K key, V value) {
        root = add(key,value,root);
        root.color = BLACK;
    }

    public void set(K key, V value) {
        Node node = containsKey(key,root);
        if(node == null){
            throw new IllegalArgumentException("要修改的值不存在");
        }
        node.value = value;
    }

    private Node remove(Node node, K key){
        if( node == null )
            return null;

        if( key.compareTo(node.key) < 0 ){
            node.left = remove(node.left , key);
            return node;
        }
        else if(key.compareTo(node.key) > 0 ){
            node.right = remove(node.right, key);
            return node;
        }
        else{   // key.compareTo(node.key) == 0

            // 待删除节点左子树为空的情况
            if(node.left == null){
                Node rightNode = node.right;
                node.right = null;
                size --;
                return rightNode;
            }

            // 待删除节点右子树为空的情况
            if(node.right == null){
                Node leftNode = node.left;
                node.left = null;
                size --;
                return leftNode;
            }

            // 待删除节点左右子树均不为空的情况

            // 找到比待删除节点大的最小节点, 即待删除节点右子树的最小节点
            // 用这个节点顶替待删除节点的位置
            Node successor = findMin(node.right);
            successor.right = removMin(node.right);
            successor.left = node.left;

            node.left = node.right = null;

            return successor;
        }

    }

    private Node findMin(Node node){
        //1     终止条件
        if(node.left==null){
            return node;
        }

        //2     递归
        return findMin(node.left);
    }

    private Node removMin(Node node){
        //终止条件
        if(node.left==null){
            Node rightNode = node.right;
            node.right = null;
            return rightNode;
        }

        //递归
        node.left = removMin(node.left);
        return node;
    }

    /**
     * 删除任意元素 若删除元素节点下只有一个节点直接接上即可,若有两个节点,则找前驱或后继,本节找前驱
     * @author weidoudou
     * @date 2023/1/1 11:52
     * @param key 请添加参数描述
     * @return V
     **/
    public V remove(K key) {
        Node node = containsKey(key,root);
        if(node != null){
            root = remove(root, key);
            return node.value;
        }
        return null;
    }

    //1     校验二分搜索树(中序遍历参考之前的中序遍历一节)
    public boolean judgeBST(){
        List<K> list = new ArrayList<>();
        inOrder(root,list);
        for(int i=1;i<list.size();i++){
            if(list.get(i-1).compareTo(list.get(i))>0){
                return false;
            }
        }
        return true;
    }

    private void inOrder(Node node, List<K> list){
        if(node==null){
            return;
        }
        inOrder(node.left,list);
        list.add(node.key);
        inOrder(node.right,list);
    }




    public static void main(String[] args){

        System.out.println("Pride and Prejudice");

        ArrayList<String> words = new ArrayList<>();
        if(FileOperation.readFile("pride-and-prejudice.txt", words)) {
            System.out.println("Total words: " + words.size());

            RBTree<String, Integer> map = new RBTree<>();
            for (String word : words) {
                if (map.contains(word))
                    map.set(word, map.get(word) + 1);
                else
                    map.add(word, 1);
            }

            System.out.println("Total different words: " + map.getSize());
            System.out.println("Frequency of PRIDE: " + map.get("pride"));
            System.out.println("Frequency of PREJUDICE: " + map.get("prejudice"));
        }

        System.out.println();
    }


}

 

 

 

测试结果:

 

Pride and Prejudice
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11


Process finished with exit code 0

 

posted on 2023-05-10 07:37  菜鸟乙  阅读(17)  评论(0编辑  收藏  举报