Java代码演示红黑树

红黑树规则

  • 1.每一个节点不是红色就是黑色的
  • 2.根节点总是黑色的
  • 3.如果节点是红色,则它的子节点必须是黑色,反之则不一定
  • 4.从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点
  • 5.空节点默认看成黑色,新添加的节点默认为红色节点
package com.at.tree;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 红黑树
 * 1.每一个节点不是红色就是黑色的
 * 2.根节点总是黑色的
 * 3.如果节点是红色,则它的子节点必须是黑色,反之则不一定
 * 4.从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点
 * 5.空节点默认看成黑色,新添加的节点默认为红色节点
 */
public class RedBlackTree<T extends Comparable<T>> {
    /**
     * 根节点
     */
    private Node<T> root;

    /**
     * 红-黑树添加节点
     */
    public boolean add(T data){
        //新的节点 -- 默认红色
        Node<T> newNode = new Node<>(data);
        //判断是否为根节点
        if (root == null){
            root = newNode;
            root.color = Color.BLACK;//将根节点的颜色该为黑色
            return true;
        }

        //非根节点
        Node<T> node = root;
        while (true){

            //1.下行查找过程中进行颜色的变换
            changeColorNode(node);

            if (newNode.data.compareTo(node.data) >= 0){
                //newNode >= node
                if (node.rightNode != null){
                    node = node.rightNode;
                }else {
                    node.rightNode = newNode;
                    newNode.parentNode = node;
                    //插入之后的恢复规则
                    if (node.color == Color.RED){
                        //获得祖父节点
                        Node gpNode = node.parentNode;
                        if (gpNode.leftNode == node){
                            //内侧子孙
                            changeColor(gpNode);
                            changeColor(newNode);
                            leftRotate(node);
                            rightRotate(gpNode);
                        }else {
                            //外侧子孙
                            changeColor(gpNode);
                            changeColor(node);
                            leftRotate(gpNode);
                        }
                    }

                    break;
                }
            }else if (newNode.data.compareTo(node.data) < 0){
                //newNode < node
                if (node.leftNode != null){
                    node = node.leftNode;
                }else {
                    node.leftNode = newNode;
                    newNode.parentNode = node;
                    //插入之后的恢复规则
                    if (node.color == Color.RED){
                        //获得祖父节点
                        Node gpNode = node.parentNode;
                        if (gpNode.leftNode == node){
                            //外侧子孙
                            changeColor(gpNode);
                            changeColor(node);
                            rightRotate(gpNode);
                        }else {
                            //内侧子孙
                            changeColor(gpNode);
                            changeColor(newNode);
                            rightRotate(node);
                            leftRotate(gpNode);
                        }
                    }
                    break;
                }
            }
        }

        return true;
    }

    /**
     * 变换节点的颜色,当黑色节点有两个红色子节点的时候
     */
    private void changeColorNode(Node<T> node){
        if (node.leftNode != null &&
                node.rightNode != null &&
                node.leftNode.color == Color.RED  &&
                node.rightNode.color == Color.RED){
            //颜色变换
            changeColor(node);
            changeColor(node.leftNode);
            changeColor(node.rightNode);

            //是否发生了红-红冲突
            Node<T> pNode = node.parentNode;
            if (pNode == null){
                //说明node本身就是根节点,根节点的原则就是必须为黑色
                node.color = Color.BLACK;
            }else if (pNode.color == Color.RED){
                //红-红冲突

                //获得祖父节点
                Node<T> gpNode = pNode.parentNode;

                //判断node是gpNode的外侧子孙还是内侧子孙
                if (gpNode.leftNode == pNode){
                    if (pNode.leftNode == node){
                        //外侧子孙,靠左

                        //1、修改gpNode的颜色
                        changeColor(gpNode);
                        //2、修改pNode的颜色
                        changeColor(pNode);
                        //3、以gpNode为顶点进行右旋
                        rightRotate(gpNode);
                    }else {
                        //内测子孙,靠左

                        //1.修改gpNode的颜色
                        changeColor(gpNode);
                        //2.修改node的颜色
                        changeColor(node);
                        //3.以pNode为顶点进行左旋
                        leftRotate(pNode);
                        //4.以gpNode为顶点进行右旋
                        rightRotate(gpNode);
                    }
                }else{
                    if (pNode.rightNode == node){
                        //外侧子孙,靠右

                        //1、修改gpNode的颜色
                        changeColor(gpNode);
                        //2、修改pNode的颜色
                        changeColor(pNode);
                        //3、以gpNode为顶点进行左旋
                        leftRotate(gpNode);
                    }else {
                        //内侧子孙,靠右

                        //1.修改gpNode的颜色
                        changeColor(gpNode);
                        //2.修改node的颜色
                        changeColor(node);
                        //3.以pNode为顶点进行右旋
                        rightRotate(pNode);
                        //4.以gpNode为顶点进行左旋
                        leftRotate(gpNode);
                    }
                }
            }
        }
    }

    /**
     * 右旋
     * 以a为顶点右旋
     *            a                        b
     *          / \                      / \
     *         b   c                     d   a
     *       / \         ->            /   / \
     *      d  e                     f   e   c
     *     /
     *    f
     */
    private void rightRotate(Node<T> node){
        //获得node的左子树
        Node<T> lNode = node.leftNode;
        //获得node的父节点
        Node<T> pNode = node.parentNode;
        //处理旋转的父级节点
        if (pNode == null){
            this.root = lNode;
        }else {
            if (pNode.leftNode == node){
                pNode.leftNode = lNode;
            }else {
                pNode.rightNode = lNode;
            }
        }
        lNode.parentNode = pNode;

        //处理lNode的右节点
        if (lNode.rightNode != null){
            node.leftNode = lNode.rightNode;
            lNode.rightNode.parentNode = node;
        }else {
            node.leftNode = null;
        }

        lNode.rightNode = node;
        node.parentNode = lNode;
    }

    /**
     * 右旋
     * 以a为顶点左旋
     *            a                        c
     *          / \                      / \
     *         b   c                    a   f
     *       /   / \         ->       / \   \
     *      d   e   f                b   e   g
     *               \             /
     *                g          d
     */
    private void leftRotate(Node<T> node){
        //获得node的左子树
        Node<T> rNode = node.rightNode;
        //获得node的父节点
        Node<T> pNode = node.parentNode;
        //处理旋转的父级节点
        if (pNode == null){
            this.root = rNode;
        }else {
            if (pNode.leftNode == node){
                pNode.leftNode = rNode;
            }else {
                pNode.rightNode = rNode;
            }
        }
        rNode.parentNode = pNode;

        //处理lNode的右节点
        if (rNode.leftNode != null){
            node.rightNode = rNode.leftNode;
            rNode.leftNode.parentNode = node;
        }else {
            node.rightNode = null;
        }

        rNode.leftNode = node;
        node.parentNode = rNode;
    }

    /**
     * 红黑树节点
     * @param <T>
     */
    private static class Node<T extends Comparable<T>>{
        T data;//节点的数据
        Color color = Color.RED;//节点的颜色

        Node<T> parentNode;//父节点的引用
        Node<T> leftNode;//左子树的引用
        Node<T> rightNode;//右子树的引用

        public Node(T data){
            this.data = data;
        }
    }

    /**
     * 颜色的枚举
     */
    private static enum Color{
        RED,
        BLACK;
    }

    /**
     * 层次遍历
     */
    public void cencibianli(){
        System.out.println("------------层次遍历-------------");
        //定义一个节点队列
        Queue<Node<T>> queue = new LinkedList<>();
        queue.add(this.root);
        while (true){
            Node<T> node = queue.poll();
            if (node == null){
                break;
            }
            System.out.println(node.data + ":" + node.color);
            if (node.leftNode != null){
                queue.add(node.leftNode);
            }
            if (node.rightNode != null){
                queue.add(node.rightNode);
            }
        }
    }

    /**
     * 转换节点颜色
     * @param node
     */
    private void changeColor(Node<T> node){
        if (node.color == Color.RED){
            node.color = Color.BLACK;
        }else {
            node.color = Color.RED;
        }
    }
}

package com.at.tree;

public class Client {

    public static void main(String[] args) {
        RedBlackTree<Integer> redBlackTree = new RedBlackTree<>();
        redBlackTree.add(78);
        redBlackTree.add(14);
        redBlackTree.add(12);
        redBlackTree.add(4);
        redBlackTree.add(7);
        redBlackTree.add(90);
        redBlackTree.add(24);
        redBlackTree.add(1);

        redBlackTree.cencibianli();
    }
}

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值