N节点的二叉树是“好奇的”,如果它是一个二进制树,其节点值为1,2,...,N并且满足
的属性好奇的二叉树的例子
4
/ \
5 2
/ \
1 3
你能给出一个算法来生成n个节点的均匀随机好奇二叉树,它在O(n)保证时间内运行吗?
假设您只能访问随机数生成器,该随机数生成器可以为[1,k]范围内的任何1< = k< = n提供(均匀分布的)随机数。假设生成器在O(1)中运行。
O(nlogn)时间解决方案也将获得我的支持。
请遵循标记二进制树的通常定义,以考虑不同的好奇二叉树。
答案 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);
}