Включение элемента в рандомизированное дерево

При построении рандомизированного дерева основное исходное положение заключается в том, что любой элемент может с одинаковой вероятностью быть корнем дерева. Причём это справедливо и для поддеревьев рандомизированного дерева. Поэтому при включении нового элемента в дерево, случайным образом выбирается включение элемента в качестве листа, или в качестве корня. Вероятность появления нового узла в корне дерева или поддерева определяется, как 1/(n+1), где n – число узлов в дереве или в поддереве. То есть, дерево выглядит так, будто элементы поступали в него в случайном порядке. Поскольку принимаемые алгоритмом решения являются случайными, при каждом выполнении алгоритма при одной и то же последовательности включений будут получаться деревья различной конфигурации. Таким образом, несмотря на увеличение трудоёмкости операции включения, за счет рандомизации получается структура дерева, близкая к сбалансированной. Благодаря сбалансированности дерева трудоёмкость в рандомизированном дереве имеет оценку О(log2n) и в среднем операции более эффективны, чем в BST-дереве.

Рекурсивный алгоритм вставки в рандомизированное дерево:

RND_Insert(t, k, data, inserted)

1. t – корень дерева или поддерева

2. k –ключ нового элемента

3. data – данные нового элемента

4. inserted – возвращаемый признак вставки

5. if t = nil

6. then tCreate_Node (k, data)

7. n[ t ] ← 1

8. inserted ← TRUE

9. return t

10. if Rand() < RAND_MAX/(n[ t ]+1)

11. then tRoot_Insert (t, k, data, ins)

12. inserted ← ins

13. return t

14. if k = key[ t ]

15. then inserted ← FALSE

16. return t

17. if k < key[t]

18. then left[ t ] ← RND_Insert (left[ t ], k, data, ins)

19. else right[ t ] ← RND_Insert (right[ t ], k, data, ins)

20. inserted ← ins

21. if inserted = TRUE

22. then n[ t ] ← n[ t ] + 1

23. return t

 

Поскольку принимаемые алгоритмом решения являются случайными, то при каждом выполнении алгоритма для одной и той же последовательности включений будут получаться различные конфигурации рандомизированного дерева. Таким образом, не смотря на увеличение трудоемкости операции включения, за счет рандомизации получается структура дерева, близкая к сбалансированной.

Поиск в рандомизированном дереве ведется по стандартному алгоритму поиска в BST – дереве. Благодаря сбалансированности дерева в среднем поиск оценивается нотацией O(log2 n) и более эффективен, чем в BST – дереве.

Недостатком приведенного алгоритма являются затраты на генерацию случайных чисел в узлах, лежащих на пути операции включения. Чтобы минимизировать эти затраты, можно вместо системного генератора случайных чисел использовать числа, которые не являются совершенно случайными, но для генерации требуют небольших затрат. Например, функцию Rand() можно заменить проверкой условия 111 mod n[t] = 3 для принятия решения о вставке в корень [4].

Второй недостаток – необходимость поддержки параметра n[t] в узлах рандомизированного дерева. Но, если этот параметр необходим по другим причинам, например для решения задач о порядковых статистиках, то этот недостаток не является решающим.

 

· Вставка элемента x во множество. Выполняется так:

Начинаем с корневого узла дерева (его адрес записан в root). Сравниваем x со значением v в этом узле. Если они равны, то мы нашли x и делать ничего не надо – выходим из процедуры. Если x меньше v, то переходим по левому указателю (left), если больше – по правому (right). Продолжаем делать так до тех пор, пока указатель, по которому надо переходить, не окажется NIL. В этом случае создаём новый узел и его адрес помещаем в этот указатель.

И не забываем ещё один нюанс. Если элемент вставляется в пустое дерево, то адрес созданного узла нужно записать в переменную root.

Приведём пример реализации:

 

procedure ins(var root: PNode; x: integer);

var

r: PNode;

begin

if root=NIL then begin

new(root);

root^.left:=NIL; root^.right:=NIL; root^.v:=x;

exit;

end;

 

r:=root;

 

repeat

if r^.v=x then exit;

 

if x<r^.v then

begin

if r^.left<>NIL then

r:=r^.left

else

begin

new(r^.left);

r:=r^.left;

r^.left:=NIL; r^.right:=NIL; r^.v:=x;

exit;

end

end

 

else

 

begin

if r^.right<>NIL then

r:=r^.right

else

begin

 

new(r^.right);

r:=r^.right;

r^.left:=NIL; r^.right:=NIL; r^.v:=x;

exit;

end;

end;

 

until false;

 

end;

 


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: