生成均匀随机的好奇二叉树

时间:2010-07-13 22:34:45

标签: algorithm puzzle

N节点的二叉树是“好奇的”,如果它是一个二进制树,其节点值为1,2,...,N并且满足

的属性
  • 树的每个内部节点都只有一个大于它的后代。
  • 1,2,...,N中的每个数字都只出现在树中一次。

好奇的二叉树的例子

  4
 / \
5   2
   / \
  1   3

你能给出一个算法来生成n个节点的均匀随机好奇二叉树,它在O(n)保证时间内运行吗?

假设您只能访问随机数生成器,该随机数生成器可以为[1,k]范围内的任何1< = k< = n提供(均匀分布的)随机数。假设生成器在O(1)中运行。

O(nlogn)时间解决方案也将获得我的支持。

请遵循标记二进制树的通常定义,以考虑不同的好奇二叉树。

2 个答案:

答案 0 :(得分:4)

“好奇的”二叉树和标准堆之间存在双射。也就是说,给定一个堆,递归地(从顶部开始)将每个内部节点与其最大的子节点交换。而且,正如我在不久前在StackOverflow中学到的那样,堆相当于1,2,...,N的排列。所以你应该做一个随机排列并把它变成一堆;或者以与进行随机排列相同的方式递归地生成堆。之后,您可以将堆转换为“好奇的树”。

答案 1 :(得分:2)

啊哈,我想我已经有了在O(N)时间内创建随机堆的方法。 (之后,在Greg Kuperberg的回答中使用方法转换成“好奇的”二叉树。)

编辑2 :用于直接制作随机最小堆的粗略伪代码。最大堆是相同的,除了插入堆中的值是反向数字顺序。

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);
}