arrow-left

All pages
gitbookPowered by GitBook
1 of 1

Loading...

4.3. Red-Black Trees

This section discusses a type of balanced binary search trees called Red-Black Trees.

Red-Black trees preserve the balance at most time by satisfying the following conditions:

  • Every node is either red or black.

  • The root and all leaves (null) are black.

  • Every red node must have two black children.

  • Every path from a given node to any of its leaves goes through the same number of black nodes.

hashtag
Red-Black Node

Let us create the class inheriting AbstractBinaryNode:

  • L2: if is_red is true, the color of this node is red; otherwise, it is black.

  • L6: the color of the node is black by default upon instantiation.

Let us the class inheriting AbstractBalancedBinarySearchTree:

Finally, let us override balance() method that handles 3 cases:

  • L3: sets the color to black if node is the root.

  • L5: if the color of node's parent is red:

What about the case when the color of node's parent is black?

The following shows a method that handles when both the parent and the uncle are red:

Are there any structural changes after this method is called?

The following shows a method that handles when the parent is red but the uncle is black:

  • L7: the case of left zig-zag.

  • L11: the case of right zig-zag.

  • L19: the case of left linear.

The followings demonstrate how the balance() method works in Red-Black trees:

How does a Red-Black tree know when it is unbalanced?

L8: checks if the color of node's uncle is also red.

  • L10: the color of node's uncle is black.

  • L21: the case of right linear.

  • RedBlackNodearrow-up-right
    RedBlackTreearrow-up-right
    public class RedBlackNode<T extends Comparable<T>> extends AbstractBinaryNode<T, RedBlackNode<T>> {
        private boolean is_red;
    
        public RedBlackNode(T key) {
            super(key);
            setToRed();
        }
    
        public void setToRed() { is_red = true; }
    
        public void setToBlack() { is_red = false; }
    
        public boolean isRed() { return is_red; }
    
        public boolean isBlack() { return !is_red; }
    }
    public class RedBlackTree<T extends Comparable<T>> extends AbstractBalancedBinarySearchTree<T, RedBlackNode<T>> {
        @Override
        public RedBlackNode<T> createNode(T key) {
            return new RedBlackNode<T>(key);
        }
    }
    @Override
    protected void balance(RedBlackNode<T> node) {
        if (isRoot(node))
            node.setToBlack();
        else if (node.getParent().isRed()) {
            RedBlackNode<T> uncle = node.getUncle();
    
            if (uncle != null && uncle.isRed())
                balanceWithRedUncle(node, uncle);
            else
                balanceWithBlackUncle(node);
        }
    }
    private void balanceWithRedUncle(RedBlackNode<T> node, RedBlackNode<T> uncle) {
        node.getParent().setToBlack();
        uncle.setToBlack();
        RedBlackNode<T> grandParent = node.getGrandParent();
        grandParent.setToRed();
        balance(grandParent);
    }
    private void balanceWithBlackUncle(RedBlackNode<T> node) {
        RedBlackNode<T> grandParent = node.getGrandParent();
    
        if (grandParent != null) {
            RedBlackNode<T> parent = node.getParent();
    
            if (grandParent.isLeftChild(parent) && parent.isRightChild(node)) {
                rotateLeft(parent);
                node = parent;
            }
            else if (grandParent.isRightChild(parent) && parent.isLeftChild(node)) {
                rotateRight(parent);
                node = parent;
            }
    
            node.getParent().setToBlack();
            grandParent.setToRed();
    
            if (node.getParent().isLeftChild(node))
                rotateRight(grandParent);
            else
                rotateLeft(grandParent);
        }
    }