Data Structures and Algorithms in Java
GitHubAuthor
  • Preface
    • Syllabus
    • Schedule
  • 0. Getting Started
    • 0.1. Environment Setup
    • 0.2. Quiz
  • 1. Java Essentials
    • 1.1. Abstraction
    • 1.2. Implementation
    • 1.3. Unit Testing
    • 1.4. Quiz
  • 2. Priority Queues
    • 2.1. Simple Priority Queues
    • 2.2. Binary Heap
    • 2.3. Unit Testing
    • 2.4. Benchmarking
    • 2.5. Quiz
  • 3. Sorting Algorithms
    • 3.1. Abstraction
    • 3.2. Comparison-based Sort
    • 3.3. Divide & Conquer Sort
    • 3.4. Distribution-based Sort
    • 3.5. Quiz
    • 3.6. Homework
  • 4. Binary Search Trees
    • 4.1. Binary Search Trees
    • 4.2. Balanced BST
    • 4.2. AVL Trees
    • 4.3. Red-Black Trees
    • 4.4. Quiz
  • 5. Tries
    • 5.1. Concept
    • 5.2. Implementation
    • 5.3. Quiz
    • 5.4. Homework
  • 6. Disjoint Sets
    • 6.1. Concept
    • 6.2. Implementation
    • 6.3. Quiz
  • 7. Graphs
    • 7.1. Implementation
    • 7.2. Cycle Detection
    • 7.3. Topological Sorting
    • 7.4. Quiz
  • 8. Minimum Spanning Trees
    • 8.1. Abstraction
    • 8.2. Prim's Algorithm
    • 8.3. Kruskal’s Algorithm
    • 8.4. Edmonds' Algorithm
    • 8.5. Quiz
    • 8.6. Homework
  • 9. Network Flow
    • 9.1. Flow Network
    • 9.2. Ford-Fulkerson Algorithm
    • 9.3. Simplex Algorithm
    • 9.3. Quiz
  • 10. Dynamic Programming
    • 10.1. Fibonacci Sequence
    • 10.2. Tower of Hanoi
    • 10.3. Longest Common Subsequence
    • 10.4. Quiz
Powered by GitBook

©2023 Emory University - All rights reserved

On this page
  • Rotation
  • Abstract Balanced Binary Search Tree

Was this helpful?

Export as PDF
  1. 4. Binary Search Trees

4.2. Balanced BST

This section discusses abstraction of binary search trees.

Previous4.1. Binary Search TreesNext4.2. AVL Trees

Last updated 2 years ago

Was this helpful?

A binary search tree gives the worst-case complexity of O(n)O(n)O(n)for searching a key when it is not balanced, where nnn is the number of nodes in the tree:

Search

Insert

Delete

Unbalanced

Balanced

To ensure the O(log⁡n)O(\log n)O(logn) complexity, it needs to be balanced at all time (or at most time).

Rotation

There are 4 cases of unbalanced trees to be considered:

  • Left linear ⇒\Rightarrow⇒ [3, 2, 1]

  • Right linear ⇒\Rightarrow⇒ [1, 2, 3]

  • Left zig-zag ⇒\Rightarrow⇒ [3, 1, 2]

  • Right zig-zag ⇒\Rightarrow⇒ [1, 3, 2]

These cases can be balanced by performing rotations as follows:

What should happen to the subtrees (red/orange/green/blue triangles) after the rotations?

Abstract Balanced Binary Search Tree

public abstract class AbstractBalancedBinarySearchTree<T extends Comparable<T>, N extends AbstractBinaryNode<T, N>> extends AbstractBinarySearchTree<T, N> {
    /**
     * Rotates the specific node to the left.
     * @param node the node to be rotated.
     */
    protected void rotateLeft(N node) {
        N child = node.getRightChild();
        node.setRightChild(child.getLeftChild());

        if (node.hasParent())
            node.getParent().replaceChild(node, child);
        else
            setRoot(child);

        child.setLeftChild(node);
    }

    /**
     * Rotates the specific node to the right.
     * @param node the node to be rotated.
     */
    protected void rotateRight(N node) {
        N child = node.getLeftChild();
        node.setLeftChild(child.getRightChild());

        if (node.hasParent())
            node.getParent().replaceChild(node, child);
        else
            setRoot(child);

        child.setRightChild(node);
    }
}

Where does node end up being after the rotations?

The followings demonstrate how the rotateLeft() method works:

Let us override the add() and remove() methods that call the abstract method balance():

@Override
public N add(T key) {
    N node = super.add(key);
    balance(node);
    return node;
}

@Override
public N remove(T key) {
    N node = findNode(root, key);

    if (node != null) {
        N lowest = node.hasBothChildren() ? removeHibbard(node) : removeSelf(node);
        if (lowest != null && lowest != node) balance(lowest);
    }

    return node;
}

/**
 * Preserves the balance of the specific node and its ancestors.
 * @param node the node to be balanced.
 */
protected abstract void balance(N node);
  • L3: calls the add() method in the super class, AbstractBinarySearchTree.

  • L4: performs balancing on node that is just added.

  • L14: performs balancing on node that is the lowest node in the tree affected by this removal.

  • L24: defines a balancing algorithm for a specific type of balanced binary search trees.

What are the worst-case complexities of the add() and remove() methods above?

Let us create an abstract class that inherits the abstract class AbstractBinarySearchTree:

O(n)O(n)O(n)
O(n)O(n)O(n)
O(n)+βO(n) + \betaO(n)+β
O(log⁡n)O(\log n)O(logn)
O(log⁡n)+αO(\log n) + \alphaO(logn)+α
O(log⁡n)+βO(\log n) + \betaO(logn)+β
AbstractBalancedBinarySearchTree