Generating uniformly random curious binary trees
如果一个n个节点的二叉树的节点值为1、2、…、n,并且满足以下属性,那么它就是"好奇的"。
- 树的每个内部节点只有一个比它大的子代。
- 1,2,…,n中的每一个数字都恰好出现在树中一次。
一个奇怪的二叉树的例子
1 2 3 4 5 | 4 / \ 5 2 / \ 1 3 |
你能给出一个算法来生成一个在O(N)保证时间内运行的n个节点的一致随机奇异二叉树吗?
假设您只能访问一个随机数生成器,对于任何1<=k<=n,该生成器都可以在[1,k]范围内给您一个(均匀分布的)随机数。假设生成器在o(1)中运行。
O(非登录)时间解决方案也会得到我的支持。
请遵循标记的二叉树的一般定义,以考虑不同的奇异二叉树。
在"好奇的"二叉树和标准堆之间有一个双射。也就是说,给定一个堆,递归地(从顶部开始)交换每个内部节点及其最大的子节点。正如我不久前在StackOverflow中了解到的,堆相当于1,2,…,n的排列,所以你应该做一个随机排列,然后把它变成一个堆;或者递归地做堆,就像你做随机排列一样。之后,您可以将堆转换为"好奇的树"。
啊哈,我想我已经知道如何在O(N)时间内创建一个随机堆了。(之后,使用GregKuperberg的答案中的方法将其转换为"好奇的"二叉树。)
编辑2:直接生成随机最小堆的粗糙伪代码。最大堆是相同的,除了插入到堆中的值是相反的数字顺序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 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); } |