Problem: Balancing a Binary Search Tree
A binary search tree can satisfy the ordering property and still have a bad shape. The ordering property says nothing about height, so the same values can end up in a tall, skewed tree where lookups are slow.
Use the binary tree node from the tree chapter:
public class Node<T> {
public T value;
public Node<T> left;
public Node<T> right;
public Node(T value) {
this.value = value;
}
}
Write this method:
public static <T> Node<T> balance(Node<T> root) {
}
An empty tree gives an empty tree, so return null.
Height-balanced means the same property the AVL tree maintains: at every node, the heights of the two subtrees differ by at most .
Here is the kind of input we want to fix. In the search tree chapter we saw that adding sorted values one at a time produces a single chain of nodes. Suppose someone built that tree by inserting the values 20 through 80 in order, so each value became the right child of the one before it:
╭────╮
│ 20 │
╰──┬─╯
└─┐
╭──┴─╮
│ 30 │
╰──┬─╯
└─┐
╭──┴─╮
│ 40 │
╰──┬─╯
└─┐
╭──┴─╮
│ 50 │
╰──┬─╯
└─┐
╭──┴─╮
│ 60 │
╰──┬─╯
└─┐
╭──┴─╮
│ 70 │
╰──┬─╯
└─┐
╭──┴─╮
│ 80 │
╰────╯
This is a valid binary search tree. Every left child is smaller than its parent, and every right child is larger. But its height is , so a lookup can take seven steps when it should take three.
We want to keep the same seven values and return this tree instead:
╭────╮
│ 50 │
╰──┬─╯
┌──────────┴──────────┐
╭──┴─╮ ╭──┴─╮
│ 30 │ │ 70 │
╰──┬─╯ ╰──┬─╯
┌────┴────┐ ┌────┴────┐
╭──┴─╮ ╭──┴─╮ ╭──┴─╮ ╭──┴─╮
│ 20 │ │ 40 │ │ 60 │ │ 80 │
╰────╯ ╰────╯ ╰────╯ ╰────╯
This tree has height , and every subtree is height-balanced.
The obvious approach is to insert every value into a fresh AVL tree. That works, and the result is balanced, because the AVL tree rotates back to balance after each insertion. But each insertion costs , so the insertions cost . Aim for .
Try it before reading the solution.