6

Given a sorted array, it is very easy to visualize a BST from it in a top-down manner. For example, if the array is [1,2,3,4,5,6,7], we can see that the root will be the middle element, that is 4. To its left there will be a subtree whose root is the middle of the array slice to the left of 4, that is 2. In the same way it will be similar in the right also.

How can we do this visualization for the bottom-up approach to constructing the BST? Basically I am trying to understand the algorithm to construct a BST from a sorted linked list, which takes O(N) in bottom-up manner, and O(Nlog N) in topdown manner. So I need to understand how it builds bottom-up.

SexyBeast
  • 7,913
  • 28
  • 108
  • 196
  • I don't follow the question. What do you mean "visualize"? Also, a sorted list is a product of an [in-order traversal](http://en.wikipedia.org/wiki/Tree_traversal#Depth-first_traversal) on a BST, thus doing an in-order traversal on a tree, you can "fill it" with the elements in your sorted list. This will be `O(n)`. If you don't have a tree you need to fill, you can build an empty complete tree, and after that - fill it as suggested. – amit Oct 02 '12 at 12:33
  • What I want is to construct the tree bottom up from a sorted list with a pen and paper, the way I can easily do with a top-down approach. – SexyBeast Oct 02 '12 at 13:16

2 Answers2

9

Consider: http://www.leetcode.com/2010/11/convert-sorted-list-to-balanced-binary.html

BinaryTree* sortedListToBST(ListNode *& list, int start, int end) {
  if (start > end) return NULL;
  // same as (start+end)/2, avoids overflow
  int mid = start + (end - start) / 2;
  BinaryTree *leftChild = sortedListToBST(list, start, mid-1);
  BinaryTree *parent = new BinaryTree(list->data);
  parent->left = leftChild;
  list = list->next;
  parent->right = sortedListToBST(list, mid+1, end);
  return parent;
}

BinaryTree* sortedListToBST(ListNode *head, int n) {
  return sortedListToBST(head, 0, n-1);
}

Let's write out some of the recursive calls:

0 1 2 3 4 5 6 7 8 -> sortedListToBST(list, 0, 3) [A]
0 1 2 3           -> sortedListToBST(list, 0, 0) [B]
0                 -> sortedListToBST(list, 0, -1) [C]
*                 -> NULL [D]

[D] will return NULL.

Now, in [C], we will have leftChild = NULL and parent = 0 (first node in the list). The parent's left child will be NULL, and the list progresses. [C] will then call sortedListToBst(1, 0), which will return NULL, so the right child of parent will also be NULL. Your tree so far looks like this:

        0
     /     \
  null     null

Now, this will be returned to the left call in [B], so leftChild = 0 = the above in [B]. The parent in [B] will set itself to 1 (the second node in the list, note that we advanced the list head in a previous call - the list is global / passed by reference). Its left child will be set to what you compute in the previous step (the above tree). Your tree now looks like this:

        1
      /
     0
  /     \
null   null

The list is advanced again, pointing to 2. A recursive call sortedListToBST(list, 2, 3) will be made from [B], which will trigger multiple recursive calls.

It's a lot to write / explain, but hopefully this sets you on the right track. It should be easier to follow on paper.

IVlad
  • 43,099
  • 13
  • 111
  • 179
  • Great explanation, but I am still not able to build the tree from the array just by looking at it. Imagine the array is `[1,2,3,4,5,6,7]`. Then were we to build the tree top-down, we would start with the middle element, that is `4`. To its left will be the middle of its left slice, that is `2`. When I come to `2`, its left child will be the middle of its left slice, that is `1`, & right child will the middle of the right slice, that is `3`. Similarly for the right side. In this manner it is very easy to draw the tree from just looking at the array top-down. How do I do the same for bottom-up? – SexyBeast Oct 02 '12 at 16:00
  • 1
    @Cupidvogel - you don't :P. Recursion is not meant to be easy to follow. For the naive algorithm it happens to be easy to do visually in this case. For the efficient algorithm it's going to be harder. You'll probably notice some patterns if you run it step by step on some examples. I haven't done it, but I'm guessing it involves building the tree in a "left-parent-right" from bottom to top as you walk the list. I wouldn't bother too much with it as long as you understand the idea behind the algorithm. Take the towers of hanoi for example - I know its recursive solution, but I -- – IVlad Oct 02 '12 at 17:33
  • 1
    -- probably wouldn't be able to apply it in an actual game. Same for other complex recursive formulas or algorithms. You need to view some of them from a more abstract perspective - just because your brain can't run the algorithm fast doesn't mean you don't understand it or that the algorithm is bad. – IVlad Oct 02 '12 at 17:35
  • @IVlad, your explanation works great for an array that you already know the sie of. But what if you have an array/list that doesn't have a determinate end? For example, what if the number of nodes that you will have to create/insert into the b-tree is unknown at the start, yet you want to create a b-tree from the bottom up? You have no idea how many inserts you have to do but you have to insert every node from the bottom up. That's the programming exercise I am working on. – SQA777 Feb 24 '22 at 00:17
1

if you have a sorted input then creating a binary Tree is simple as it looks coz dividing the array by three parts left+mid+right at each stage recursively and attaching left and right to the parent/mid while backtracking will create the binary tree (Note its not Binary Search Tree that we built, but it is BST becoz of the nature of the input that it was sorted). Since we build the tree while backtracking, each element(root+internal nodes) might be accessed atmost 2 times (1 time when partitioning and other time when backtracking and assigning children) so the time complexity maybe atmost O(2n) or O(n) in general. Though it might look as if we build tree from top-down, since we perform recursion, but actually we build the tree bottom-up coz the nodes are constructed and interconnected to form subtrees when backtracking.

This also has an interesting fact that the the tree formed will surely be a complete binary tree which has all levels completely filled except last level where nodes are filled from left to right.

A Perfect(Complete+Balanced) Binary Tree can be obtained where all levels are completely filled including last level when input size is a power of 2.

A balanced(abs(leftHeight)-abs(rightHeight)<=1) Tree built using this technique can be a Perfect binary Tree or Complete binary Tree with last level having only leftmost one node.

This works for both Arrays and linked Lists.

mahee96
  • 705
  • 6
  • 15