Привет, сегодня поговорим про дерево двоичного поиска, обещаю рассказать все что знаю. Для того чтобы лучше понимать что такое
дерево двоичного поиска, обход дерева, binary search tree, tree traversal , настоятельно рекомендую прочитать все из категории Структуры данных.
обход дерева (известный также как поиск по дереву) — вид обхода графа[en], обусловливающий процесс посещения (проверки и/или обновления) каждого узла структуры дерева данных ровно один раз. Такие обходы классифицируются по порядку, в котором узлы посещаются. Алгоритмы в статье относятся к двоичным деревьям, но могут быть обобщены и для других деревьев.
Типы обхода деревьев
В отличие от связных списков, одномерных массивов и других линейных структур данных, которые канонически обходятся в линейном порядке, деревья можно обходить различными путями. Деревья можно обходить «в глубину» или «в ширину». Существует три основных способа обхода «в глубину»
- прямой (pre-order)
- центрированный (in-order)
- обратный (post-order) . Кроме этих трех основных схем, возможны более сложные гибридные схемы, такие как алгоритмы поиска с ограниченной глубиной[en], подобные поиску в глубину с итеративным углублением[en]
Большинство студентов, только что окончивших инженерные специальности, или тех, кто еще учится, будут иметь свежую концепцию бинарных деревьев поиска. Но большинство людей, которые уже много лет не учились в колледже, будут иметь не очень ясное представление о деревьях двоичного поиска, если только они не использовали его или связанные с ним концепции в своей работе. В этом руководстве я покажу, как реализовать
дерево двоичного поиска (BST) в Java, а также покажу следующие операции:
- Вставка / построение BST
- Нахождение узла максимального значения в BST
- Нахождение узла минимального значения в BST
- Inorder Traversal of BST
- Предварительный просмотр BST
- Постордерный обход BST
Что такое двоичное дерево поиска (BST)?
Дерево двоичного поиска (BST) - это структура данных двоичного дерева со специальной функцией, в которой в хранилище значений на каждом узле больше или равно значению, хранящемуся в его левом дочернем дочернем элементе, и меньше, чем значение, хранящееся в его правом дочернем дочернем элементе. Давайте посмотрим на пример BST:
В приведенном выше примере вы можете видеть, что в каждом узле значение в левом дочернем узле меньше или равно значению в узле, а значение в правом дочернем элементе больше, чем значение в узле.
Построение двоичного дерева поиска (BST)
Теперь, когда мы увидели, как выглядит BST, позвольте мне показать вам, как можно построить BST и вставить узлы в дерево, реализовав алгоритм на Java. Основная идея заключается в том, что на каждом узле мы сравниваем с вставляемым значением. Если значение меньше, мы проходим через левое поддерево, а если значение больше, мы проходим через правое поддерево. Предположим, нам нужно вставить значение 64 в приведенный выше BST, давайте посмотрим на узлы, пройденные до того, как оно было вставлено в нужное место:
Каждый узел в BST представлен следующим java-классом:
6 |
public Node( int value) { |
Давайте посмотрим на код на Java для достижения вышеуказанной логики:
1 |
public class BinarySearchTree { |
4 |
public void insert( int value){ |
5 |
Node node = new Node<>(value); |
12 |
insertRec(root, node); |
16 |
private void insertRec(Node latestRoot, Node node){ |
18 |
if ( latestRoot.value > node.value){ |
20 |
if ( latestRoot.left == null ){ |
21 |
latestRoot.left = node; |
25 |
insertRec(latestRoot.left, node); |
29 |
if (latestRoot.right == null ){ |
30 |
latestRoot.right = node; |
34 |
insertRec(latestRoot.right, node); |
Нахождение максимального и минимального значения в BST
Если вы заметили в приведенном выше примере, что крайний левый узел имеет наименьшее значение, а крайний правый узел имеет наибольшее значение. Это связано с сортированным характером дерева.
Используя этот принцип, приведенные ниже методы возвращают нам самое низкое и самое высокое значение в дереве двоичного поиска:
2 |
* Returns the minimum value in the Binary Search Tree. |
4 |
public int findMinimum(){ |
9 |
while (currNode.left != null ){ |
10 |
currNode = currNode.left; |
12 |
return currNode.value; |
16 |
* Returns the maximum value in the Binary Search Tree |
18 |
public int findMaximum(){ |
24 |
while (currNode.right != null ){ |
25 |
currNode = currNode.right; |
27 |
return currNode.value; |
Обход двоичного дерева поиска (BST)
Обход дерева или BST в этом случае - это посещение каждого из узлов, присутствующих в дереве, и выполнение некоторой операции со значением, присутствующим в узле, который в этом случае будет печатать значение, присутствующее в узле. Когда мы проходим по дереву, мы должны посетить значение, присутствующее в узле, затем правое поддерево узла и левое поддерево . Посещение правого и левого поддерева будет рекурсивной операцией. Порядок, в котором мы выполняем три операции, т.е. посещение значения, правого поддерева и левого поддерева, дает три метода обхода:
- Inorder Traversal
- Предварительный заказ
- Пост порядковый обход
Inorder Traversal
При этом обходе сначала посещается левое поддерево данного узла, затем печатается значение в данном узле, а затем посещается правое поддерево данного узла. Этот процесс рекурсивно применяется ко всем узлам в дереве, пока либо левое поддерево не станет пустым, либо правое поддерево не станет пустым.
Применяя обход Inorder для данного примера, мы получаем: 3, 10, 17, 25, 30, 32, 38, 40, 50, 78, 78, 93.
2 |
* Printing the contents of the tree in an inorder way. |
4 |
public void printInorder(){ |
6 |
System.out.println( "" ); |
10 |
* Helper method to recursively print the contents in an inorder way |
12 |
private void printInOrderRec(Node currRoot){ |
13 |
if ( currRoot == null ){ |
16 |
printInOrderRec(currRoot.left); |
17 |
System.out.print(currRoot.value+ ", " ); |
18 |
printInOrderRec(currRoot.right); |
Обход предзаказа
В этом обходе сначала печатается значение в данном узле, затем посещается левое поддерево данного узла, а затем посещается правое поддерево данного узла. Об этом говорит сайт https://intellect.icu . Этот процесс рекурсивно применяется ко всем узлам в дереве, пока либо левое поддерево не станет пустым, либо правое поддерево не станет пустым.
Применяя обход Preorder для данного примера, мы получаем: 40, 25, 10, 3, 17, 32, 30, 38, 78, 50, 78, 93.
2 |
* Printing the contents of the tree in a Preorder way. |
4 |
public void printPreorder() { |
5 |
printPreOrderRec(root); |
6 |
System.out.println( "" ); |
10 |
* Helper method to recursively print the contents in a Preorder way |
12 |
private void printPreOrderRec(Node currRoot) { |
13 |
if (currRoot == null ) { |
16 |
System.out.print(currRoot.value + ", " ); |
17 |
printPreOrderRec(currRoot.left); |
18 |
printPreOrderRec(currRoot.right); |
Пост порядковый обход
При этом обходе сначала просматривается левое поддерево данного узла, затем обходится правое поддерево данного узла, а затем печатается значение в данном узле. Этот процесс рекурсивно применяется ко всем узлам в дереве, пока либо левое поддерево не станет пустым, либо правое поддерево не станет пустым.
Применяя обход Postorder для данного примера, мы получаем: 3, 17, 10, 30, 38, 32, 25, 50, 93, 78, 78, 40.
2 |
* Printing the contents of the tree in a Postorder way. |
4 |
public void printPostorder() { |
5 |
printPostOrderRec(root); |
6 |
System.out.println( "" ); |
10 |
* Helper method to recursively print the contents in a Postorder way |
12 |
private void printPostOrderRec(Node currRoot) { |
13 |
if (currRoot == null ) { |
16 |
printPostOrderRec(currRoot.left); |
17 |
printPostOrderRec(currRoot.right); |
18 |
System.out.print(currRoot.value + ", " ); |
Полный код, который строит дерево для примера, описанного в этом коде, и распечатывает максимальное, минимальное значение, обход порядка, обход предварительного заказа и обход пост-заказа, можно найти ниже:
2 |
* Represents a node in the Binary Search Tree. |
5 |
//The value present in the node. |
8 |
//The reference to the left subtree. |
11 |
//The reference to the right subtree. |
14 |
public Node( int value) { |
21 |
* Represents the Binary Search Tree. |
23 |
public class BinarySearchTree { |
25 |
//Refrence for the root of the tree. |
28 |
public BinarySearchTree insert( int value) { |
29 |
Node node = new Node<>(value); |
36 |
insertRec(root, node); |
40 |
private void insertRec(Node latestRoot, Node node) { |
42 |
if (latestRoot.value > node.value) { |
44 |
if (latestRoot.left == null ) { |
45 |
latestRoot.left = node; |
48 |
insertRec(latestRoot.left, node); |
51 |
if (latestRoot.right == null ) { |
52 |
latestRoot.right = node; |
55 |
insertRec(latestRoot.right, node); |
61 |
* Returns the minimum value in the Binary Search Tree. |
63 |
public int findMinimum() { |
68 |
while (currNode.left != null ) { |
69 |
currNode = currNode.left; |
71 |
return currNode.value; |
75 |
* Returns the maximum value in the Binary Search Tree |
77 |
public int findMaximum() { |
83 |
while (currNode.right != null ) { |
84 |
currNode = currNode.right; |
86 |
return currNode.value; |
90 |
* Printing the contents of the tree in an inorder way. |
92 |
public void printInorder() { |
93 |
printInOrderRec(root); |
94 |
System.out.println( "" ); |
98 |
* Helper method to recursively print the contents in an inorder way |
100 |
private void printInOrderRec(Node currRoot) { |
101 |
if (currRoot == null ) { |
104 |
printInOrderRec(currRoot.left); |
105 |
System.out.print(currRoot.value + ", " ); |
106 |
printInOrderRec(currRoot.right); |
110 |
* Printing the contents of the tree in a Preorder way. |
112 |
public void printPreorder() { |
113 |
printPreOrderRec(root); |
114 |
System.out.println( "" ); |
118 |
* Helper method to recursively print the contents in a Preorder way |
120 |
private void printPreOrderRec(Node currRoot) { |
121 |
if (currRoot == null ) { |
124 |
System.out.print(currRoot.value + ", " ); |
125 |
printPreOrderRec(currRoot.left); |
126 |
printPreOrderRec(currRoot.right); |
130 |
* Printing the contents of the tree in a Postorder way. |
132 |
public void printPostorder() { |
133 |
printPostOrderRec(root); |
134 |
System.out.println( "" ); |
138 |
* Helper method to recursively print the contents in a Postorder way |
140 |
private void printPostOrderRec(Node currRoot) { |
141 |
if (currRoot == null ) { |
144 |
printPostOrderRec(currRoot.left); |
145 |
printPostOrderRec(currRoot.right); |
146 |
System.out.print(currRoot.value + ", " ); |
151 |
public class BinarySearchTreeDemo { |
153 |
public static void main(String[] args) { |
154 |
BinarySearchTree bst = new BinarySearchTree(); |
167 |
System.out.println( "Inorder traversal" ); |
170 |
System.out.println( "Preorder Traversal" ); |
173 |
System.out.println( "Postorder Traversal" ); |
174 |
bst.printPostorder(); |
176 |
System.out.println( "The minimum value in the BST: " + bst.findMinimum()); |
177 |
System.out.println( "The maximum value in the BST: " + bst.findMaximum()); |
Обход дерева.
Вам предлагается решить эту задачу в соответствии с описанием задачи, используя любой язык, который вы знаете.
Реализуйте двоичное дерево, в котором каждый узел несет целое число, и реализуйте обход до, в порядке, после и в порядке уровней. Используйте эти обходы для вывода следующего дерева:
1
/ \
/ \
/ \
2 3
/ \ /
4 5 6
/ / \
7 8 9
Правильный вывод должен выглядеть так:
предзаказ: 1 2 4 7 5 3 6 8 9
порядок: 7 4 2 5 1 8 6 9 3
отправитель: 7 4 5 2 8 9 6 3 1
порядок уровней: 1 2 3 4 5 6 7 8 9
Вау!! 😲 Ты еще не читал? Это зря!
Алгоритмы поиска на графах
|
Неинформированные методы |
- Двунаправленный поиск
- Лучевой поиск
- Лексикографический поиск в ширину
- Поиск в ширину
- Поиск по критерию стоимости
- Поиск в глубину
- Поиск с возвратом
- Поиск восхождением к вершине
- Поиск с ограничением глубины
- Поиск в глубину с итеративным углублением
|
Информированные методы |
- Альфа-бета-отсечение
- Метод ветвей и границ
- Поиск по первому наилучшему совпадению
- A*
- B*
- D*
- Поиск точки перехода
- IDA*
- Рекурсивный поиск по первому наилучшему совпадению
- SMA*
|
Кратчайшие пути |
- Волновой алгоритм
- Алгоритм Беллмана — Форда
- Алгоритм Дейкстры
- Алгоритм Джонсона
- Алгоритм Левита
- Алгоритм Флойда — Уоршелла
- Поиск по краям
|
Минимальное остовное дерево |
- Алгоритм Борувки
- Алгоритм Прима
- Алгоритм Краскала
|
Другое |
- Алгоритм Британского музея
- Алгоритм Эдмондса
- Обход дерева
- Алгоритм ближайшего соседа в задаче коммивояжера
|
На этом все! Теперь вы знаете все про дерево двоичного поиска, Помните, что это теперь будет проще использовать на практике. Надеюсь, что теперь ты понял что такое дерево двоичного поиска, обход дерева, binary search tree, tree traversal
и для чего все это нужно, а если не понял, или есть замечания,
то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории
Структуры данных
Комментарии
Оставить комментарий
Структуры данных
Термины: Структуры данных