46

Reference: I was asked this question @MS SDE interview, 3rd round. And it's not a homework problem. I also gave it a thought and mentioning my approach below.

Question: Modify a BST so that it becomes as balanced as possible. Needless to mention, you should do it as efficient as possible.

Hint: Interviewer said that this is a logical question, if you think differently you will get the answer. No difficult coding involved.
--> Having said that, I do not think he was expecting me to point to AVL/RB Trees.

My Solution: I proposed that, I would do inorder traversal of tree, take middle element as root of new tree(lets call it new root). Then go to the left part of middle element, take its middle element as root of left subtree of tree rooted new root. Similarly do for right part. Doing this recursively will give the optimal balanced BST.

Why I am posting it here: But he was not satisfied with the answer :( So, is there really a way of doing this w/o going for weights/RB coloring strategy, or was he just fooling around with me? Please put in your expert thoughts.

Duplicate? No! I know there is this question but the solution proposed by requester is too complicated, and other one talks about AVL trees.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
ADJ
  • 1,182
  • 2
  • 14
  • 26
  • I realize that my approach has a flaw, when new nodes will be added BST has to be reconstructed to make it balanced. – ADJ Dec 22 '12 at 09:35
  • 2
    You should ask your interviewer why s/he was not satisfied with you answer. Your assumption to not use a RB tree might be incorrect: the only way to be sure is to ask your interviewer. – Bart Kiers Dec 22 '12 at 09:38
  • Please give a precise definition of "as balanced as possible". Also, is it an static operation: tree comes in, balanced tree goes out, or dynamic: has to remain balanced for insert, etc. (RB would be the answer there I suppose). – Ciro Santilli OurBigBook.com May 25 '16 at 08:23
  • @CiroSantilli巴拿馬文件六四事件法轮功 as amit said in below answer - "Balanced as possible" = complete (or full) binary tree1. You cannot get more balanced that it. – ADJ May 30 '16 at 05:51
  • @Tingya thanks for clarifying! I've edited the title to make it clearer. Feel free to modify it further or rollback if you prefer. ;-) – Ciro Santilli OurBigBook.com May 30 '16 at 07:54

4 Answers4

45

You might want to look into the Day-Stout-Warren algorithm, which is an O(n)-time, O(1)-space algorithm for reshaping an arbitrary binary search tree into a complete binary tree. Intuitively, the algorithm works as follows:

  1. Using tree rotations, convert the tree into a degenerate linked list.
  2. By applying selective rotations to the linked list, convert the list back into a completely balanced tree.

The beauty of this algorithm is that it runs in linear time and requires only constant memory overhead; in fact, it just reshapes the underlying tree, rather than creating a new tree and copying over the old data. It is also relatively simple to code up.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
17

"Balanced as possible" = complete (or full) binary tree1. You cannot get more balanced that it.

The solution is simple - build an "empty" complete binary tree, and iterate the new tree and the input tree (simultaneously) in inorder-traversal to fill the complete tree.

When you are done, you have the most balanced tree you can get, and time complexity of this approach is O(n).


EDIT:
This should be done following these steps:

  1. Build a dummy complete tree with n nodes. All the values to each node will be initialized to some garbage value.
  2. Create two iterators: (1) originalIter for the original tree, (2) newIter for the new (initialized with garbage) tree. Both iterators will return elements in in-order traversal.
  3. Do the following to fill the tree with the values from the original:

     while (originalIter.hasNext()):
          newIter.next().value = originalIter.next().value
    

(1) (From Wikipedia): A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible

amit
  • 175,853
  • 27
  • 231
  • 333
  • Hi Amit, thank you for your answer, but I did not quite understand your stmt: build an "empty" complete binary tree, and iterate the new tree and the input tree (simultaneously) in inorder-traversal to fill the complete tree. Can you please elaborate? – ADJ Dec 24 '12 at 11:27
  • 1
    Space complexity of O(n) is overhead right with this approach? – Anudeep Gade Sep 11 '15 at 08:23
  • what order of node values (not nodes) does each iteration generate? – pitosalas Apr 01 '16 at 12:25
  • Is this algorithm has a name? Because it's as efficient as DSW (regarding time) and much much easier to understand. – Ömer Faruk Almalı Mar 02 '17 at 15:59
12

The DSW algorithm can solve this is O(n) time. The algorithm goes as follows:

1] Using right-rotation operations, turn the tree into a linked list
   (a.k.a. backbone or vine)
2] Rotate every second node of the backbone about its parent to turn
   the backbone into a perfectly balanced BST. 

Reference

saurav.varma
  • 280
  • 2
  • 10
1

This will convert your normal BST into a balanced BST with minimum possible height in O(n). First, save all your nodes sorted into a vector. Then, the root is the mid element and recursively build a tree from 0 to mid-1 as its left and build a tree from mid+1 to vector.size()-1 as its right child. After all these steps root keeps the balanced BST with the min-height.

    import java.util.Vector;

        public class ConvertBSTIntoBalanced {

            public static void main(String[] args) {
                TreeNode node1 = new TreeNode(1);
                TreeNode node2 = new TreeNode(2);
                TreeNode node3 = new TreeNode(3);
                TreeNode node4 = new TreeNode(4);
                node1.right = node2;
                node2.right = node3;
                node3.right = node4;
                ConvertBSTIntoBalanced convertBSTIntoBalanced = new ConvertBSTIntoBalanced();
                TreeNode balancedBSTRoot = convertBSTIntoBalanced.balanceBST(node1);
            }

            private void saveNodes(TreeNode node, Vector<TreeNode> nodes) {
                if (node == null)
                    return;
                saveNodes(node.left, nodes);
                nodes.add(node);
                saveNodes(node.right, nodes);
            }

            private TreeNode buildTree(Vector<TreeNode> nodes, int start, int end) {
                if (start > end)
                    return null;
                int mid = (start + end) / 2;
                TreeNode midNode = nodes.get(mid);
                midNode.left = buildTree(nodes, start, mid - 1);
                midNode.right = buildTree(nodes, mid + 1, end);
                return midNode;
            }

            public TreeNode balanceBST(TreeNode root) {
                Vector<TreeNode> nodes = new Vector<>();
                saveNodes(root, nodes);
                return buildTree(nodes, 0, nodes.size() - 1);
            }

        public class TreeNode {

        public Integer val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(Integer x) {
            val = x;
        }

    }

        }

I hope it helps.

Mohammad
  • 6,024
  • 3
  • 22
  • 30