views:

178

answers:

2

A binary tree of N nodes is 'curious' if it is a binary tree whose node values are 1, 2, ..,N and which satisfy the property that

  • Each internal node of the tree has exactly one descendant which is greater than it.
  • Every number in 1,2, ..., N appears in the tree exactly once.

Example of a curious binary tree

  4
 / \
5   2
   / \
   1  3

Can you give an algorithm to generate a uniformly random curious binary tree of n nodes, which runs in O(n) guaranteed time?

Assume you only have access to a random number generator which can give you a (uniformly distributed) random number in the range [1, k] for any 1 <= k <= n. Assume the generator runs in O(1).

An O(nlogn) time solution will get my upvote too.

Please follow the usual definition of labelled binary trees being distinct, to consider distinct curious binary trees.

+5  A: 

There is a bijection between "curious" binary trees and standard heaps. Namely, given a heap, recursively (starting from the top) swap each internal node with its largest child. And, as I learned in StackOverflow not long ago, a heap is equivalent to a permutation of 1,2,...,N. So you should make a random permutation and turn it into a heap; or recursively make the heap in the same way that you would have made a random permutation. After that you can convert the heap to a "curious tree".

Greg Kuperberg
How will you do that in deterministic O(n) time?
Moron
It doesn't look difficult to everything in O(n(log n)) time with sorting methods. But linear time? The conversion from a random heap to a random "curious tree" is linear time, there's a bit of luck there. I would ask whether you can make a random heap in linear time. You can make a random permutation in linear time using Knuth sorting. Not sure about a random heap.
Greg Kuperberg
That is the puzzle :)
Moron
+1 for solving the tougher part of the problem IMHO
Jason S
@Greg: I believe we can use the Range Minimum Query algorithms (O(n) time O(n) space) to solve the problem in linear time using this approach.
Moron
+2  A: 

Aha, I think I've got how to create a random heap in O(N) time. (after which, use approach in Greg Kuperberg's answer to transform into "curious" binary tree.)

edit 2: Rough pseudocode for making a random min-heap directly. Max-heap is identical except the values inserted into the heap are in reverse numerical order.

struct Node {
   Node left, right;
   Object key;
   constructor newNode() { 
     N = new Node; 
     N.left = N.right = null; 
     N.key = null;
   }
}

function create-random-heap(RandomNumberGenerator rng, int N)
{
   Node heap = Node.newNode();
   // Creates a heap with an "incomplete" node containing a null, and having
   // both child nodes as null.

   List incompleteHeapNodes = [heap];
   // use a vector/array type list to keep track of incomplete heap nodes.

   for k = 1:N
   {
      // loop invariant: incompleteHeapNodes has k members. Order is unimportant.

     int m = rng.getRandomNumber(k);
     // create a random number between 0 and k-1
     Node node = incompleteHeapNodes.get(m);
     // pick a random node from the incomplete list, 
     // make it a complete node with key k.
     // It is ok to do so since all of its parent nodes
     // have values less than k.
     node.left = Node.newNode();
     node.right = Node.newNode();
     node.key = k;

     // Now remove this node from incompleteHeapNodes
     // and add its children. (replace node with node.left,
     // append node.right)

     incompleteHeapNodes.set(m, node.left);
     incompleteHeapNodes.append(node.right);

     // All operations in this loop take O(1) time.
   }

   return prune-null-nodes(heap);
}

// get rid of all the incomplete nodes.
function prune-null-nodes(heap)
{
   if (heap == null || heap.key == null)
      return null;
   heap.left = prune-null-nodes(heap.left);
   heap.right = prune-null-nodes(heap.right);
}
Jason S
+1: Looks right to me!
Moron
I wonder if this produces a distribution of heaps that is the same as if you had a random permutation and inserted into a standard heap each number in the permutation in order. No idea how to prove or disprove they're the same distribution.
Jason S
@Jason: Pick any particular heap and consider the probability of obtaining that heap using your method. I believe we can show that the probability is exactly 1/n!.
Moron
I can believe that... but is the other distribution (picking random permutation, inserting the elements one by one) also equally distributed? I guess if there are n! different heaps that result, it would have to be, otherwise there would be less than n! different heaps (there are only n! permutations) and that would be leaving some out.
Jason S
Yes, the other method picking a random distribution and creating a heap (but not by inserting one by one, see: http://stackoverflow.com/questions/3153620/counting-treaps) also works. In fact that can also be made O(n) I believe, but the algorithm there is more complicated.
Moron
It works. The algorithm inserts numbers in increasing order to a list represented as a heap structure. The vacant leaves of the heap represent the gaps where each new element can be inserted. The algorithm assumes that the gaps are equally likely, and they are. It is a heap version of a linear time algorithm to make a random permutation. (If you wanted the permutation, the heap can also be read out in linear time.) Interesting.
Greg Kuperberg
how do you "read out" a heap into a permutation? Do you use infix ordering traversal? Seems like the heap ordering property would mess things up somehow.
Jason S
@Greg: btw I figured I could probably have written it to use an array-implementation heap w/ all its in-place benefits (then the incompleteHeapNodes list could just be a list of indices), but didn't want to mess with that so used a tree structure instead for simplicity.
Jason S
@Jason: An array might not be right, as the array assumes an 'almost complete' tree, while you are trying to generate arbitrary trees here. If you read the link in my earlier comment, you will see that the inorder of a heap corresponds exactly to a unique permutation. So when Greg says 'read-out' I believe he means do inorder traversal.
Moron
That's right, infix traversal. That's the bijection between heaps and permutations.
Greg Kuperberg
@Moron: (an oxymoronic username, btw!) Oh right, I was thinking of complete binary heaps http://en.wikipedia.org/wiki/Binary_heap which have balanced depths -- so my answer deals with arbitrary binary trees having the heap-ordering property but not the balanced property.
Jason S
@Jason: :-). Yes the question is essentialy about arbitrary binary trees with the heap-ordering property (with the 'curious' twist), so your answer is spot on! I will accept your answer after a waiting a few more days. I believe you and Greg both deserve more upvotes than what you have currently!
Moron