Генерация равномерно случайных любопытных двоичных деревьев
двоичное дерево из N узлов "любопытно", если это двоичное дерево, значения узлов которого равны 1, 2,..N и, которые удовлетворяют свойству, что
- каждый внутренний узел дерева имеет ровно один потомок, который больше его.
- каждое число 1,2, ..., N появляется в дереве ровно один раз.
пример любопытного двоичного дерева
4
/
5 2
/
1 3
можете ли вы дать алгоритм для генерации равномерно случайного любопытного двоичного дерева n узлы, которые работают в o (n) гарантированное время?
предположим, что у вас есть доступ только к генератору случайных чисел, который может дать вам (равномерно распределенное) случайное число в диапазоне [1, k] для любого 1
решение O(nlogn) time также получит мой upvote.
пожалуйста, следуйте обычному определению помеченных двоичных деревьев, чтобы рассмотреть различные любопытные двоичные деревья.
2 ответов
Ага, я думаю, что у меня есть, как создать случайную кучу в O(N) времени. (после чего используйте подход в ответе Грега Куперберга для преобразования в "любопытное" двоичное дерево.)
Изменить 2: грубый псевдокод для создания случайной мин-кучи напрямую. Max-heap идентичен, за исключением значений, вставленных в кучу, в обратном числовом порядке.
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);
}
существует биекция между" любопытными " бинарными деревьями и стандартными кучами. А именно, учитывая кучу, рекурсивно (начиная с вершины) замените каждый внутренний узел на его самый большой дочерний. И, как я узнал в StackOverflow не так давно, куча эквивалентна перестановке 1,2..., N. таким образом, вы должны сделать случайную перестановку и превратить ее в кучу; или рекурсивно сделать кучу так же, как вы сделали бы случайную перестановку. После этого вы можете преобразовать кучи к "странное дерево".