Рандомизированное бинарное дерево поиска — различия между версиями
Строка 11: | Строка 11: | ||
<tex>P[size(L) = i] = \frac{1}n, i = 1..n</tex>. | <tex>P[size(L) = i] = \frac{1}n, i = 1..n</tex>. | ||
}} | }} | ||
− | Из определения следует, что каждый ключ в RBST размера n может оказаться корнем с вероятностью <tex>\frac{1}{n}</tex>. | + | Из определения следует, что каждый ключ в RBST размера n может оказаться корнем с вероятностью <tex dpi="150">\frac{1}{n}</tex>. |
Идея RBST состоит в том, что хранимое дерево постоянно является рандомизированным бинарным деревом поиска. Далее подробно будет описана реализация операций над RBST, которая позволит добиться этой цели. Заметим лишь, что хранение RBST в памяти ничем не отличается от хранения обычного дерева поиска: хранится указатель на корень; в каждой вершине хранятся указатели на её сыновей. | Идея RBST состоит в том, что хранимое дерево постоянно является рандомизированным бинарным деревом поиска. Далее подробно будет описана реализация операций над RBST, которая позволит добиться этой цели. Заметим лишь, что хранение RBST в памяти ничем не отличается от хранения обычного дерева поиска: хранится указатель на корень; в каждой вершине хранятся указатели на её сыновей. | ||
− | + | Похожие идеи используются в [[Декартово дерево| декартовом дереве]], поэтому во многих русскоязычных ресурсах термин '''рандомизированное бинарное дерево поиска''' используется как синонимическое название декартового дерева и [[Декартово дерево по неявному ключу|декартового дерева по неявному ключу]]. | |
==Операции== | ==Операции== | ||
Строка 23: | Строка 23: | ||
===Вставка=== | ===Вставка=== | ||
− | Рассмотрим рекурсивный алгоритм вставки ключа <tex>x</tex> в RBST, состоящее из <tex>n</tex> вершин. С вероятностью <tex dpi = "150">\frac{1}{n+1}</tex> вставим ключ в корень дерева, используя процедуру <tex>\mathrm{insert\_at\_root}</tex>. С вероятностью <tex dpi = "150">1 - \frac{1}{n+1} = \frac{n}{n+1}</tex> вставим его в правое поддерево, если он больше корня, или в левое поддерево, если меньше. Ниже приведён псевдокод процедуры вставки <tex>\mathrm{insert}</tex>, процедуры <tex>\mathrm{insert\_at\_root}</tex>, а также процедуры <tex>\mathrm{split(k)}</tex>, разбивающей дерево на два поддерева, в одном из которых все ключи строго меньше <tex>k</tex>, а в другом больше, либо равны; приведена достаточно очевидная рекурсивная реализация. (через Node обозначен тип вершины дерева, дерево представляется как указатель на корень) | + | Рассмотрим рекурсивный алгоритм вставки ключа <tex>x</tex> в RBST, состоящее из <tex>n</tex> вершин. С вероятностью <tex dpi = "150">\frac{1}{n+1}</tex> вставим ключ в корень дерева, используя процедуру <tex>\mathrm{insert\_at\_root}</tex>. С вероятностью <tex dpi = "150">1 - \frac{1}{n+1} = \frac{n}{n+1}</tex> вставим его в правое поддерево, если он больше корня, или в левое поддерево, если меньше. Ниже приведён псевдокод процедуры вставки <tex>\mathrm{insert}</tex>, процедуры <tex>\mathrm{insert\_at\_root}</tex>, а также процедуры <tex>\mathrm{split(k)}</tex>, разбивающей дерево на два поддерева, в одном из которых все ключи строго меньше <tex>k</tex>, а в другом больше, либо равны; приведена достаточно очевидная рекурсивная реализация. (через <tex>Node</tex> обозначен тип вершины дерева, дерево представляется как указатель на корень) |
'''Node''' insert(T, x) | '''Node''' insert(T, x) | ||
Строка 47: | Строка 47: | ||
'''return''' T | '''return''' T | ||
− | split(T, x, L, R) | + | split(T, x, L, R) <font color="green"> // разделяет дерево T по x, результат - деревья L и R</font> |
'''if''' size(T) == 0 | '''if''' size(T) == 0 | ||
L = RBST() | L = RBST() | ||
Строка 53: | Строка 53: | ||
'''else if''' x < T.key | '''else if''' x < T.key | ||
R = T | R = T | ||
− | split (T.left, x, L, R.left) | + | split(T.left, x, L, R.left) |
'''else''' | '''else''' | ||
L = T | L = T | ||
− | split (T.right, x, L.right, R) | + | split(T.right, x, L.right, R) |
Далее рассмотрим как меняется свойство дерева быть рандомизированным при вставке в него ключей. | Далее рассмотрим как меняется свойство дерева быть рандомизированным при вставке в него ключей. | ||
{{Лемма | {{Лемма | ||
− | |statement= Пусть после операции <tex>\mathrm{split}</tex> от дерева <tex>T</tex> по ключу <tex>x</tex> были получены деревья <tex>T_{L}</tex> и <tex>T_{R}</tex>. Тогда если <tex>T</tex> было рандомизированным бинарным деревом поиска, содержащим множество ключей <tex>K</tex>, то деревья <tex>T_{L}</tex> и <tex>T_{R}</tex> {{---}} рандомизированные бинарные деревья поиска, содержащие соответственно множества ключей <tex>K_{L} = \{y \in K | + | |statement= Пусть после операции <tex>\mathrm{split}</tex> от дерева <tex>T</tex> по ключу <tex>x</tex> были получены деревья <tex>T_{L}</tex> и <tex>T_{R}</tex>. Тогда если <tex>T</tex> было рандомизированным бинарным деревом поиска, содержащим множество ключей <tex>K</tex>, то деревья <tex>T_{L}</tex> и <tex>T_{R}</tex> {{---}} рандомизированные бинарные деревья поиска, содержащие соответственно множества ключей <tex>K_{L} = \{y \in K \mid y < x\}</tex> и <tex>K_{R} = \{y \in K \mid y > x\}</tex>. |
|proof= | |proof= | ||
Применим индукцию по <tex>n</tex> {{---}} размеру дерева. Если <tex>n = 0</tex>, то лемма верна (получим два пустых дерева). | Применим индукцию по <tex>n</tex> {{---}} размеру дерева. Если <tex>n = 0</tex>, то лемма верна (получим два пустых дерева). | ||
Строка 71: | Строка 71: | ||
(пусть событие <tex>A</tex> {{---}} <tex>z</tex> является коренем <tex>T_{L}</tex>) | (пусть событие <tex>A</tex> {{---}} <tex>z</tex> является коренем <tex>T_{L}</tex>) | ||
− | <tex dpi = "150">P[A | + | <tex dpi = "150">P[A \mid y < x] = \frac{P[A \; \wedge \; y < x]}{P[y < x]} = \frac{1 / n}{m / n} = \frac{1}{m}</tex> |
Случай, когда <tex>x < y</tex> симметричен рассмотренному. | Случай, когда <tex>x < y</tex> симметричен рассмотренному. | ||
Строка 154: | Строка 154: | ||
Тогда: | Тогда: | ||
− | <tex>P[A] = P[A | + | <tex>P[A] = P[A \mid B] \cdot P[B] + P[A\mid\neg B] \cdot P[\neg B] = P[C] \cdot 1/n + P[D\mid\neg B] \cdot (n - 1)/n = </tex> |
<tex dpi = "150">\frac{1}{n - 1} \cdot \frac{1}{n} + \frac{1}{n - 1} \cdot \frac{n - 1}{n} = \frac{1}{n - 1}</tex>. | <tex dpi = "150">\frac{1}{n - 1} \cdot \frac{1}{n} + \frac{1}{n - 1} \cdot \frac{n - 1}{n} = \frac{1}{n - 1}</tex>. | ||
}} | }} | ||
Строка 167: | Строка 167: | ||
*[[Декартово дерево по неявному ключу]] | *[[Декартово дерево по неявному ключу]] | ||
− | == | + | == Источники информации == |
+ | * [http://en.wikipedia.org/wiki/Random_binary_tree Wikipedia {{---}} Random binary tree] | ||
* [http://en.wikipedia.org/wiki/Treap Wikipedia {{---}} Treap] | * [http://en.wikipedia.org/wiki/Treap Wikipedia {{---}} Treap] | ||
− | |||
− | |||
− | |||
* Martinez, Conrado; Roura, Salvador (1997), "Randomized binary search trees", Journal of the ACM 45 | * Martinez, Conrado; Roura, Salvador (1997), "Randomized binary search trees", Journal of the ACM 45 | ||
* Seidel, Raimund; Aragon, Cecilia R. [http://people.ischool.berkeley.edu/~aragon/pubs/rst96.pdf «Randomized Search Trees»], 1996 г. | * Seidel, Raimund; Aragon, Cecilia R. [http://people.ischool.berkeley.edu/~aragon/pubs/rst96.pdf «Randomized Search Trees»], 1996 г. |
Версия 19:13, 24 мая 2015
Рандомизированное бинарное дерево поиска (англ. Randomized binary search tree, RBST) — структура данных, реализующая бинарное дерево поиска.
Содержание
Основная идея и связанные определения
Как известно, можно подобрать такую последовательность операций с бинарным деревом поиска в наивной реализации, что его глубина будет пропорциональна количеству ключей, а следовательно запрос будет выполняться за . Поэтому, если поддерживать инвариант "случайности" в дереве, то можно добиться того, что математическое ожидание глубины дерева будет небольшим. Дадим рекурсивное определение рандомизированного бинарного дерева поиска (RBST).
Определение: |
Пусть
| — бинарное дерево поиска. Тогда
Из определения следует, что каждый ключ в RBST размера n может оказаться корнем с вероятностью
.Идея RBST состоит в том, что хранимое дерево постоянно является рандомизированным бинарным деревом поиска. Далее подробно будет описана реализация операций над RBST, которая позволит добиться этой цели. Заметим лишь, что хранение RBST в памяти ничем не отличается от хранения обычного дерева поиска: хранится указатель на корень; в каждой вершине хранятся указатели на её сыновей.
Похожие идеи используются в декартовом дереве, поэтому во многих русскоязычных ресурсах термин рандомизированное бинарное дерево поиска используется как синонимическое название декартового дерева и декартового дерева по неявному ключу.
Операции
Операции обхода дерева, поиска ключа, поиска максимума/минимума, поиск следующего/предыдущего элемента выполняются как в обычном дереве поиска, т.к. не меняют структуру дерева.
Вставка
Рассмотрим рекурсивный алгоритм вставки ключа
в RBST, состоящее из вершин. С вероятностью вставим ключ в корень дерева, используя процедуру . С вероятностью вставим его в правое поддерево, если он больше корня, или в левое поддерево, если меньше. Ниже приведён псевдокод процедуры вставки , процедуры , а также процедуры , разбивающей дерево на два поддерева, в одном из которых все ключи строго меньше , а в другом больше, либо равны; приведена достаточно очевидная рекурсивная реализация. (через обозначен тип вершины дерева, дерево представляется как указатель на корень)Node insert(T, x) int r = random(0 .. size(T)) if r == n T = insert_at_root(T, x) if x < root.key T = insert(T.left, x) else T = insert(T.right, x) return T
Заметим, что если дерево пусто, то
с вероятностью 1 делает корнем.Node insert_at_root(T, x) // вставляем в дерево T ключ x L = RBST() // создать пустые L и R R = RBST() split(T, x, L, R) T = RBST() // создать пустое T T.key = x T.left = L T.left = R return T
split(T, x, L, R) // разделяет дерево T по x, результат - деревья L и R if size(T) == 0 L = RBST() R = RBST() else if x < T.key R = T split(T.left, x, L, R.left) else L = T split(T.right, x, L.right, R)
Далее рассмотрим как меняется свойство дерева быть рандомизированным при вставке в него ключей.
Лемма: |
Пусть после операции от дерева по ключу были получены деревья и . Тогда если было рандомизированным бинарным деревом поиска, содержащим множество ключей , то деревья и — рандомизированные бинарные деревья поиска, содержащие соответственно множества ключей и . |
Доказательство: |
Применим индукцию по — размеру дерева. Если , то лемма верна (получим два пустых дерева).Пусть , и лемма верна при всех меньших размерах дерева.. Пусть также . Если , то — корень , — левое поддерево , а рекурсивно вызовется от , разделив его на — правое поддерево —, и , которые по предположению индукции будут рандомизированными бинарными деревьями поиска. Но также является RBST, т.к. является поддеревом .Итак для того, чтобы доказать, что — рандомизированное бинарное дерево поиска, осталось показать, что любая его вершина с вероятностью окажется в корне, где — размер . Действительно:(пусть событие — является коренем )Случай, когда симметричен рассмотренному. |
Теорема: |
Если — рандомизированное бинарное дерево поиска, содержащее множество ключей , , тогда процедура вернёт рандомизированное бинарное дерево поиска , содержащее множество ключей . |
Доказательство: |
Применим индукцию по — размеру дерева. Если , то теорема верна: после операции получим дерево с корнем и двумя пустыми поддеревьями.Пусть , и теорема верна при всех меньших размерах дерева. Возможны два случая: вставляется в корень или рекурсивно в одно из поддеревьев.В первом случае правое и левое поддеревья Во втором случае корень у дерева останется прежнем. Заметим, что для каждого по лемме являются рандомизированными BST, а также вероятность того, что окажется в корне, равна . Т.е. новое дерево — рандомизированное BST. вероятность быть корнем была , а корнем он останется с вероятностью , тогда для каждого вероятность быть корнем равна . По предположению же индукции поддерево, в которое вставляется становится рандомизированным бинарным деревом поиска; а т.к. другое поддерево корня было рандомизированным, то новое дерево — рандомизированное BST. |
Пусть
— множество ключей, — какая-то фиксированная перестановка элементов . Из приведённой выше теоремы следует, что если в изначально пустое дерево добавлять ключи P по порядку, то получим дерево , являющееся RBST.Удаление
Алгоритм удаления использует операцию
— слияние двух деревьев, удовлетворяющих условию: все ключи в одном из деревьев меньше ключей во втором. Для того, чтобы удалить некоторый ключ из RBST сначала найдём вершину с этим ключом в дереве, используя стандартный алгоритм поиска. Если вершина не найдена, то выходим из алгоритма; в противном случае сливаем правое и левое поддеревья (заметим, что ключи в левом поддереве меньше ключей в правом), удаляем , а корень образовавшегося дерева делаем новым сыном родителя . Псевдокод процедур удаления и слияния приведён ниже.Node remove(T, x) // удаляет ключ x из дерева T if size(T) == 0 T = RBST() return T // вернуть пустое поддерево if x < T.key T.left = remove(T.left, x) else if x > T.key T.right = remove(T.right, x) else Q = RBST() Q = merge(T.left, T.right) T = Q return T
Node merge(L, R) // сливает деревья L и R, результат - дерево T int m = L.size int n = R.size int total = m + n if total == 0 T = RBST() return T // вернуть пустое поддерево int r = random(1 .. total) if r < m L.right = merge(L.right, R) // с вероятностью m / (m + n) return L if r < m R.left = merge(L, R.left) // с вероятностью m / (m + n) return R
Докажем, что данный алгоритм оставляет рандомизированное дерево рандомизированным.
Лемма: |
Пусть и — рандомизированные бинарные деревья поиска, содержащие соответственно множества ключей и , причём (то есть каждый элемент меньше каждого элемента ). Тогда операция вернёт рандомизированное бинарное дерево поиска, содержащее множество ключей = . |
Доказательство: |
Пусть Пусть и — размеры и соответственно. Применим индукцию по и . Если или , то лемма верна. и , пусть также или . Без потери общности делаем корнем . После рекурсивного слияния правого поддерева и получим рандомизированное бинарное дерево поиска (которое является правым поддеревом нового дерева). Левое же поддерево нового дерева тоже рандомизированное. Также верно, что для любого вероятность быть корнем равна : действительно, вероятность оказаться в корне в до слияния равна , вероятность того, что элемент останется корнем после слияния равна ; осталось применить правило умножения. |
Теорема: |
Если — рандомизированное бинарное дерево поиска, содержащее множество ключей , тогда процедура вернёт рандомизированное бинарное дерево поиска , содержащее множество ключей |
Доказательство: |
Если удаляемый элемент отсутствует в дереве, то теорема верна. Пусть (дерево не пусто), — размер . Докажем теорему по индукции по . Для теорема очевидным образом верна. Пусть , и предположим, что теорема верна для всех деревьев размера меньше .Возможно два случая: если — корень , то по лемме, после удаления получим рандомизированное бинарное дерево поиска; если же — не корень , то рекурсивно удаляется из поддерева исходного дерева, и по предположению индукции после удаления получаем рандомизированное BST. Осталось лишь показать, что для любого вероятность оказаться корнем после удаления равна .Введём обозначения: событие — является коренем ;событие — был корнем (до операции );событие — стал корнем после операции (но до этого им не являлся);событие — был корнем (до операции );Тогда: . |
Анализ времени работы
Очевидно, что время работы приведённых алгоритмов пропорционально глубине дерева. Но т.к. математическое ожидание глубины рандомизированного бинарного дерева поиска есть
, где — число вершин в дереве, то математическое ожидание времени работы поиска, вставки и удаления — также .См. также
Источники информации
- Wikipedia — Random binary tree
- Wikipedia — Treap
- Martinez, Conrado; Roura, Salvador (1997), "Randomized binary search trees", Journal of the ACM 45
- Seidel, Raimund; Aragon, Cecilia R. «Randomized Search Trees», 1996 г.
- Randomized binary search trees. Lecture notes from a course by Jeff Erickson at UIUC.