Дерево поиска, наивная реализация — различия между версиями
(сам поправил) |
Yulya3102 (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
− | [[Файл:Binary_search_tree.svg.png|right| | + | [[Файл:Binary_search_tree.svg.png|right|300px|thumb|Бинарное дерево поиска из 9 элементов]]'''Бинарное дерево поиска (англ. binary search tree, BST)''' - структура данных для работы с динамическими множествами. |
− | Бинарное дерево поиска обладает следующим свойством: если <tex>x</tex> - узел бинарного дерева с ключом <tex>k</tex>, то все узлы в левом поддереве должны иметь ключи, меньшие | + | Бинарное дерево поиска обладает следующим свойством: если <tex>x</tex> - узел бинарного дерева с ключом <tex>k</tex>, то все узлы в левом поддереве должны иметь ключи, меньшие <tex>k</tex>, а в правом поддереве большие <tex>k</tex>. |
== Операции в бинарном дереве поиска == | == Операции в бинарном дереве поиска == | ||
=== Обход дерева поиска === | === Обход дерева поиска === | ||
Для вывода всех ключей бинарного дерева поиска в отсортированном порядке используется простой алгоритм (англ. ''inorder tree traversal''). | Для вывода всех ключей бинарного дерева поиска в отсортированном порядке используется простой алгоритм (англ. ''inorder tree traversal''). | ||
− | + | inorderTreeWalk(Node x) | |
− | if | + | if x != null |
− | + | inorderTreeWalk(x.left) | |
− | print(x.key) | + | print(x.key) |
− | + | inorderTreeWalk(x.right) | |
Данный алгоритм выполняет обход за время <tex>O(n)</tex>, поскольку процедура вызывается ровно два раза для каждого узла дерева. Корректность данного алгоритма следует из свойств бинарного дерева поиска. | Данный алгоритм выполняет обход за время <tex>O(n)</tex>, поскольку процедура вызывается ровно два раза для каждого узла дерева. Корректность данного алгоритма следует из свойств бинарного дерева поиска. | ||
=== Поиск элемента === | === Поиск элемента === | ||
− | [[Файл:Bst search.png|thumb| | + | [[Файл:Bst search.png|thumb|318px|Поиск элемента 4]] |
− | Для поиска элемента в бинарном дереве поиска можно воспользоваться следующей процедурой. | + | Для поиска элемента в бинарном дереве поиска можно воспользоваться следующей процедурой, которая принимает в качестве параметров корень дерева и искомый ключ. Для каждого узла функция сравнивает значение его ключа с искомым ключом. Если ключи одинаковы, то функция возвращает текущий узел, в противном случае функция вызывается рекурсивно для левого или правого поддерева. Узлы, которые посещает функция образуют нисходящий путь от корня, так что время ее работы <tex>O(h)</tex>, где <tex>h</tex> - высота дерева. |
− | + | treeSearch(Node x, key k) | |
− | if | + | if x == null or k == x.key |
− | return x | + | return x |
− | if | + | if k < x.key |
− | return | + | return treeSearch(x.left, k) |
else | else | ||
− | return | + | return treeSearch(x.right, k) |
− | + | ||
=== Поиск минимума и максимума === | === Поиск минимума и максимума === | ||
Чтобы найти минимальный элемент в бинарном дереве поиска, необходимо просто следовать указателям left от корня дерева, пока не встретится значение null. Если у вершины есть левое поддерево, то по свойству бинарного дерева поиска в нем хранятся все элементы с меньшим ключом. Если его нет, значит эта вершина и есть минимальная. Аналогично ищется и максимальный элемент. Для этого нужно следовать правым указателям. | Чтобы найти минимальный элемент в бинарном дереве поиска, необходимо просто следовать указателям left от корня дерева, пока не встретится значение null. Если у вершины есть левое поддерево, то по свойству бинарного дерева поиска в нем хранятся все элементы с меньшим ключом. Если его нет, значит эта вершина и есть минимальная. Аналогично ищется и максимальный элемент. Для этого нужно следовать правым указателям. | ||
− | + | treeMinimum(Node x) | |
− | while | + | while x.left != null |
− | x = x.left | + | x = x.left |
− | return x | + | return x |
− | + | treeMaximum(Node x) | |
− | while | + | while x.right != null |
− | x = x.right | + | x = x.right |
− | return x | + | return x |
Данные функции принимают корень дерева, и возвращают минимальный(максимальный) элемент в дереве. Обе процедуры выполняются за время <tex>O(h)</tex>. | Данные функции принимают корень дерева, и возвращают минимальный(максимальный) элемент в дереве. Обе процедуры выполняются за время <tex>O(h)</tex>. | ||
=== Поиск следующего и предыдущего элемента === | === Поиск следующего и предыдущего элемента === | ||
− | + | Если у узла есть правое поддерево, то следующий за ним элемент будет минимальным элементом в этом поддереве. Если у него нет правого поддерева, то нужно следовать вверх, пока не встретим узел, который является левым дочерним узлом своего родителя. Поиск предыдущего выполнятся аналогично. Если у узла есть левое поддерево, то следующий за ним элемент будет максимальным элементом в этом поддереве. Если у него нет левого поддерева, то нужно следовать вверх, пока не встретим узел, который является правым дочерним узлом своего родителя. | |
− | if | + | treeNext(Node x) |
− | return | + | if x.right != null |
− | y = x.parent | + | return treeMinimum(x.right) |
− | while | + | y = x.parent |
− | x = y | + | while y != null and x == y.right |
− | y = y.parent | + | x = y |
− | return y | + | y = y.parent |
+ | return y | ||
− | + | treePrev(Node x) | |
− | if | + | if x.left != null |
− | return | + | return treeMaximum(x.left) |
− | y = x.parent | + | y = x.parent |
− | while | + | while y != null and x == y.left |
− | x = y | + | x = y |
− | y = y.parent | + | y = y.parent |
− | return y | + | return y |
− | + | Обе операции выполняются за время <tex>O(h)</tex>. | |
=== Вставка === | === Вставка === | ||
Операция вставки работает аналогично поиску элемента, только при обнаружении нулевого указателя нужно подвесить на него вставляемый элемент. Приведем итеративную реализацию этого алгоритма. | Операция вставки работает аналогично поиску элемента, только при обнаружении нулевого указателя нужно подвесить на него вставляемый элемент. Приведем итеративную реализацию этого алгоритма. | ||
− | + | treeInsert(Node x, Node z) // корень дерева, вставляемый элемент | |
− | + | Node y = null | |
− | while | + | while x != null |
− | y = x | + | y = x |
− | if | + | if z.key > x.key |
− | x = x.right | + | x = x.right |
else | else | ||
− | x = x.left | + | x = x.left |
− | z.parent = y | + | z.parent = y |
− | if | + | if z.key > y.key |
− | y.right = z | + | y.right = z |
else | else | ||
− | y.left = z | + | y.left = z |
Время работы алгоритма <tex>O(h)</tex>. | Время работы алгоритма <tex>O(h)</tex>. | ||
=== Удаление === | === Удаление === | ||
Строка 76: | Строка 77: | ||
|- | |- | ||
|'''Удаление листа''' | |'''Удаление листа''' | ||
− | | [[Файл:Bst_del1.png | + | | [[Файл:Bst_del1.png]] |
|- | |- | ||
|'''Удаление узла с одним дочерним узлом''' | |'''Удаление узла с одним дочерним узлом''' | ||
− | | [[Файл:Bst_del2.png | + | | [[Файл:Bst_del2.png]] |
|- | |- | ||
|'''Удаление узла с двумя дочерними узлами''' | |'''Удаление узла с двумя дочерними узлами''' | ||
− | | [[Файл:Bst_del3.png | + | | [[Файл:Bst_del3.png]] |
|- | |- | ||
|'''Удаление корня''' | |'''Удаление корня''' | ||
− | | [[Файл:Bst_del4.png | + | | [[Файл:Bst_del4.png]] |
|} | |} | ||
− | + | treeDelete(Node t, Node z) // корень дерева, удаляемый элемент | |
− | + | Node x, y | |
− | if | + | if z.left == null or z.right == null |
− | y = z | + | y = z |
else | else | ||
− | y = | + | y = treeNext(z) |
− | if | + | if y.left != null |
− | x = y.left | + | x = y.left |
else | else | ||
− | x = y.right | + | x = y.right |
− | if | + | if x != null |
− | x.parent = y.parent | + | x.parent = y.parent |
− | if | + | if y.parent == null |
− | t = x | + | t = x |
else | else | ||
− | if | + | if y == y.parent.left |
− | y.parent.left = x | + | y.parent.left = x |
else | else | ||
− | y.parent.right = x | + | y.parent.right = x |
− | + | if y != z | |
− | + | z.key = y.key | |
− | + | z.data = y.data | |
− | + | return y | |
== Литература == | == Литература == |
Версия 16:27, 9 июня 2012
Бинарное дерево поиска обладает следующим свойством: если
- узел бинарного дерева с ключом , то все узлы в левом поддереве должны иметь ключи, меньшие , а в правом поддереве большие .Содержание
Операции в бинарном дереве поиска
Обход дерева поиска
Для вывода всех ключей бинарного дерева поиска в отсортированном порядке используется простой алгоритм (англ. inorder tree traversal).
inorderTreeWalk(Node x) if x != null inorderTreeWalk(x.left) print(x.key) inorderTreeWalk(x.right)
Данный алгоритм выполняет обход за время
, поскольку процедура вызывается ровно два раза для каждого узла дерева. Корректность данного алгоритма следует из свойств бинарного дерева поиска.Поиск элемента
Для поиска элемента в бинарном дереве поиска можно воспользоваться следующей процедурой, которая принимает в качестве параметров корень дерева и искомый ключ. Для каждого узла функция сравнивает значение его ключа с искомым ключом. Если ключи одинаковы, то функция возвращает текущий узел, в противном случае функция вызывается рекурсивно для левого или правого поддерева. Узлы, которые посещает функция образуют нисходящий путь от корня, так что время ее работы
, где - высота дерева.treeSearch(Node x, key k) if x == null or k == x.key return x if k < x.key return treeSearch(x.left, k) else return treeSearch(x.right, k)
Поиск минимума и максимума
Чтобы найти минимальный элемент в бинарном дереве поиска, необходимо просто следовать указателям left от корня дерева, пока не встретится значение null. Если у вершины есть левое поддерево, то по свойству бинарного дерева поиска в нем хранятся все элементы с меньшим ключом. Если его нет, значит эта вершина и есть минимальная. Аналогично ищется и максимальный элемент. Для этого нужно следовать правым указателям.
treeMinimum(Node x) while x.left != null x = x.left return x
treeMaximum(Node x) while x.right != null x = x.right return x
Данные функции принимают корень дерева, и возвращают минимальный(максимальный) элемент в дереве. Обе процедуры выполняются за время
.Поиск следующего и предыдущего элемента
Если у узла есть правое поддерево, то следующий за ним элемент будет минимальным элементом в этом поддереве. Если у него нет правого поддерева, то нужно следовать вверх, пока не встретим узел, который является левым дочерним узлом своего родителя. Поиск предыдущего выполнятся аналогично. Если у узла есть левое поддерево, то следующий за ним элемент будет максимальным элементом в этом поддереве. Если у него нет левого поддерева, то нужно следовать вверх, пока не встретим узел, который является правым дочерним узлом своего родителя.
treeNext(Node x) if x.right != null return treeMinimum(x.right) y = x.parent while y != null and x == y.right x = y y = y.parent return y
treePrev(Node x) if x.left != null return treeMaximum(x.left) y = x.parent while y != null and x == y.left x = y y = y.parent return y
Обе операции выполняются за время
.Вставка
Операция вставки работает аналогично поиску элемента, только при обнаружении нулевого указателя нужно подвесить на него вставляемый элемент. Приведем итеративную реализацию этого алгоритма.
treeInsert(Node x, Node z) // корень дерева, вставляемый элемент Node y = null while x != null y = x if z.key > x.key x = x.right else x = x.left z.parent = y if z.key > y.key y.right = z else y.left = z
Время работы алгоритма
.Удаление
Для удаления узла из бинарного дерева поиска нужно рассмотреть три возможные ситуации. Если у узла нет дочерних узлов, то у его родителя нужно просто заменить указатель на null. Если у узла есть только один дочерний узел, то нужно создать новую связь между родителем удаляемого узла и его дочерним узлом. Наконец, если у узла два дочерних узла, то нужно найти следующий за ним элемент(у этого элемента не будет левого потомка) и переместить его на место удаляемого узла. Время работы алгоритма
.Случай | Иллюстрация |
---|---|
Удаление листа | |
Удаление узла с одним дочерним узлом | |
Удаление узла с двумя дочерними узлами | |
Удаление корня |
treeDelete(Node t, Node z) // корень дерева, удаляемый элемент Node x, y if z.left == null or z.right == null y = z else y = treeNext(z) if y.left != null x = y.left else x = y.right if x != null x.parent = y.parent if y.parent == null t = x else if y == y.parent.left y.parent.left = x else y.parent.right = x if y != z z.key = y.key z.data = y.data return y
Литература
1. Кормен, Т., Лейзерсон, Ч., Ривест, Р., Штайн, К. Алгоритмы: построение и анализ = Introduction to Algorithms / Под ред. И. В. Красикова. — 2-е изд. — М.: Вильямс, 2005. — 1296 с. — ISBN 5-8459-0857-4