【数据结构与算法】JAVA实现自定向下的红黑树

JAVA实现自定向下的红黑树

主要是记录自己的内容,具体原理可能不够详细,代码可以参考。

红黑树

红黑树是AVL树的一种流行的变种。
红黑树的操作再最坏的情况下花费O(logN)的时间
参考:参考:《数据结构与算法分析:JAVA语言描述》P362
红黑树的插入、删除操作都较为复杂,本代码已实现插入操作,但书上的删除操作虽然看起来简单,但实在难以实现,网上的删除操作资料过于复杂(需大量分类讨论)。如有大佬有较为简洁的实现方式,不吝赐教。

红黑树 的特点

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

  • 每个节点可以为红色和黑色
  • 根节点为黑色
  • 如果一个节点为红色,那么其子节点必须是黑色
  • 从一个节点到一个null引用的每条路径必须包含相同数量的黑色节点
    使用以上着色法则的红黑树的高度最多为2log(N+1),这就能保证其操作的时间花费为O(logN)

代码实现

package chapter12;

import chapter04.MyCustomException;

public class RedBlackTree<T extends Comparable<? super T>> {
    private final Node<T> header;  // 不是真正的根节点,但其右子树指向真正的根
    private final Node<T> nullNode;  // 表示空节点,相当于null
    private static final int RED = 0;
    private static final int BLACK = 1;

    private Node<T> current;  // 当前节点
    private Node<T> parent;  // 父节点
    private Node<T> grand;  // 祖父
    private Node<T> great;  // 曾祖父

    private static class Node<T> {
        T element;
        Node<T> left;
        Node<T> right;
        int color;

        Node(T element) {
            this(element, null, null);
        }

        Node(T element, Node<T> left, Node<T> right) {
            this.element = element;
            this.left = left;
            this.right = right;
            this.color = BLACK;
        }
    }

    // *********************************************************************************************************
    public RedBlackTree() {
        nullNode = new Node<>(null);
        nullNode.left = nullNode.right = nullNode;
        header = new Node<>(null);
        header.left = header.right = nullNode;
    }

    public void makeEmpty() {
        header.right = nullNode;
    }

    public boolean isEmpty() {
        return header.right == nullNode;
    }

    public void insert(T element) {
        current = parent = grand = header;
        nullNode.element = element;
        while (compare(element, current) != 0) {
            great = grand;
            grand = parent;
            parent = current;
            current = compare(element, current) < 0 ? current.left : current.right;
            // 如果两个遇到两个儿子都为红色的情况,则进行颜色翻转
            if (current.left.color == RED && current.right.color == RED) {
                handleReorient(element);
            }
        }
        // 该元素element已存在,则不进行操作
        if (current != nullNode) {
            return;
        }
        // 该元素element不存在,则将该元素放入对应位置中(叶子节点中)
        current = new Node<>(element, nullNode, nullNode);
        if (compare(element, parent) < 0) {
            parent.left = current;
        } else {
            parent.right = current;
        }
        handleReorient(element);  // 进行涂色
    }

    public boolean contains(T element) {
        nullNode.element = element;
        current = header.right;
        while (true) {
            if( element.compareTo( current.element ) < 0 )
                current = current.left;
            else if( element.compareTo( current.element ) > 0 )
                current = current.right;
            else return current != nullNode;
        }
    }

    public T findMin() {
        if (isEmpty()) {
            throw new MyCustomException();
        }
        return findMin(header.right).element;
    }

    public T findMax() {
        if (isEmpty()) {
            throw new MyCustomException();
        }
        return findMax(header.right).element;
    }

    public void printTree() {
        if (isEmpty()) {
            throw new MyCustomException();
        } else {
            printTree(header.right);
        }
    }

    // *********************************************************************************************************
    // 比较element与节点node的元素大小
    private int compare(T element, Node<T> node) {
        if (node == header) {
            return 1;
        }
        return element.compareTo(node.element);
    }

    // 进行涂色操作
    private void handleReorient(T element) {
        current.color = RED;
        current.left.color = BLACK;
        current.right.color = BLACK;
        // 如果父节点也为红色,则需要进行旋转
        if (parent.color == RED) {
            grand.color = RED;
            // 如果为之字形,则需要进行两次单旋转
            if ((compare(element, grand) < 0) != (compare(element, parent) < 0)) {
                parent = rotate(element, grand);  // 一次单选择
            }
            // 如果为一字型,则只需进行一次单旋转
            current = rotate(element, great);  // 一次单选择

            current.color = BLACK;
        }
        // 根节点的颜色应始终为黑色
        header.right.color = BLACK;
    }

    // 进行单旋转
    private Node<T> rotate(T element, Node<T> parent) {
        if (compare(element, parent) < 0) {
            if (compare(element, parent.left) < 0) {
                return parent.left = rotateWithLeftChild(parent.left);  // LL
            } else {
                return parent.left = rotateWithRightChild(parent.left);  // LR
            }
        } else {
            if (compare(element, parent.right) < 0) {
                return parent.right = rotateWithLeftChild(parent.right);  // RL
            } else {
                return parent.right = rotateWithRightChild(parent.right);  // RR
            }
        }
    }

    // 左一字型的单旋转
    private Node<T> rotateWithLeftChild(Node<T> t) {
        Node<T> tmp = t.left;
        t.left = tmp.right;
        tmp.right = t;
        return tmp;
    }

    // 右一字型的单旋转
    private Node<T> rotateWithRightChild(Node<T> t) {
        Node<T> tmp = t.right;
        t.right = tmp.left;
        tmp.left = t;
        return tmp;
    }

    private Node<T> findMin(Node<T> node) {
        if (node.left == nullNode) {
            return node;
        } else {
            return findMin(node.left);
        }
    }

    private Node<T> findMax(Node<T> node) {
        if (node.right == nullNode) {
            return node;
        } else {
            return findMin(node.right);
        }
    }

    private void printTree(Node<T> node) {
        if (node != nullNode) {
            printTree(node.left);
            System.out.println(node.element);
            printTree(node.right);
        }
    }

    // *********************************************************************************************************
    public static void main(String[] args) {
        RedBlackTree<String> redBlackTree = new RedBlackTree<>();
        redBlackTree.insert("GG");
        redBlackTree.insert("TT");
        redBlackTree.insert("OO");
        redBlackTree.insert("BB");
        redBlackTree.insert("NN");
        redBlackTree.insert("LL");
        redBlackTree.insert("GG");
        redBlackTree.insert("UU");
        redBlackTree.printTree();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大枫树

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值