September 11
BST - Построение бинарного дерева поиска
Блок-схема BST: Операции вставки, поиска, удаления и обхода
- Вставка (insertNode):
- Если корень пуст (nullptr), создать новый узел и вернуть его.
- Иначе, если значение меньше данных корня – рекурсивно вставить в левое поддерево.
- Если больше – рекурсивно вправо.
- Возвратить обновлённый корень.
- Поиск (searchNode):
- Если корень пуст или совпадает с искомым значением – вернуть корень.
- Если искомое больше – рекурсивно ищем в правом поддереве.
- Если меньше – в левом.
- Удаление (deleteNode):
- Рекурсивно пройти по дереву, найти узел.
- Если узел имеет одного или нет детей – возвратить ребёнка (или nullptr).
- Если два ребёнка – найти минимальный в правом поддереве, скопировать его значение и рекурсивно удалить.
- Обход (inorderTraversal):
Как строится схема
- Строится по принципу: старт → логический выбор → рекурсия → выход.
- Любая операция вызывает себя для дочерних узлов, пока не встретит базовый случай (nullptr).
- Все ветки дерева формируются сравнением значения вставляемого, искомого или удаляемого с текущим узлом.
#include <iostream>
// Структура узла бинарного дерева поиска (BST)
struct Node {
int data; // Значение узла
Node* left; // Указатель на левое поддерево (меньшие значения)
Node* right; // Указатель на правое поддерево (большие значения)
// Конструктор для инициализации узла с заданным значением, указатели пустые
Node(int d) : data(d), left(nullptr), right(nullptr) {}
};
// Функция вставки нового значения в BST
Node* insert(Node* root, int data) {
// Если дерево пустое, создаём новый узел и возвращаем его как новый корень
if (!root) return new Node(data);
// Если значение меньше текущего узла, вставляем рекурсивно в левое поддерево
if (data < root->data) root->left = insert(root->left, data);
// Если значение больше – в правое поддерево
else if (data > root->data) root->right = insert(root->right, data);
// Возвращаем текущий корень изменённого (возможно) поддерева
return root;
}
// Симметричный (inorder) обход дерева — вывод элементов в отсортированном порядке
void inorder(Node* r) {
if (!r) return; // Базовый случай: если узла нет, выйти
inorder(r->left); // Сначала рекурсивно обойти левое поддерево
std::cout << r->data << " "; // Вывести значение текущего узла
inorder(r->right); // Затем обойти правое поддерево
}
// Функция поиска узла с заданным значением в BST
Node* search(Node* r, int k) {
// Если достигнут конец пути или найден узел с ключом, вернуть его
if (!r || r->data == k) return r;
// Рекурсивно искать в левом или правом поддереве в зависимости от сравнения
return (k < r->data) ? search(r->left, k) : search(r->right, k);
}
// Функция удаления узла с заданным значением из BST
Node* del(Node* r, int d) {
if (!r) return nullptr; // Если дерево пустое, просто вернуть nullptr
// Если значение меньше корня, удалить в левом поддереве
if (d < r->data) r->left = del(r->left, d);
// Если больше, удалить в правом поддереве
else if (d > r->data) r->right = del(r->right, d);
else {
// Найден узел для удаления
// Если у узла нет левого ребёнка, вернуть его правого ребёнка
// (возможно nullptr), удаляя текущий узел
if (!r->left) {
Node* t = r->right;
delete r;
return t;
}
// Аналогично если нет правого ребёнка, вернуть левого
if (!r->right) {
Node* t = r->left;
delete r;
return t;
}
// Если есть оба ребёнка
// Найти минимальный узел в правом поддереве (inorder successor)
Node* t = r->right;
while (t->left) t = t->left;
// Скопировать значение этого минимального узла в текущий
r->data = t->data;
// Удалить этот минимальный узел из правого поддерева рекурсивно
r->right = del(r->right, t->data);
}
// Вернуть (возможно обновлённый) корень поддерева
return r;
}
int main() {
Node* root = nullptr; // Изначально дерево пустое
// Вставляем несколько значений, формируя BST
for (int n : {50,30,20,40,70,60,80})
root = insert(root, n);
// Выводим дерево симметричным обходом (значения по возрастанию)
inorder(root);
std::cout << "\n";
// Удаляем узел со значением 20
root = del(root, 20);
inorder(root);
std::cout << "\n";
// Вставляем узел со значением 25
root = insert(root, 25);
inorder(root);
std::cout << "\n";
// Пытаемся найти узел со значением 25 и выводим результат поиска
std::cout << (search(root, 25) ? "Есть 25\n" : "Нет 25\n");
return 0;
}
class Node:
def __init__(self, d):
self.data = d # Значение узла
self.left = self.right = None # Левый и правый потомки (изначально пусты)
def insert(root, d):
# Вставка значения d в дерево с корнем root
if not root: # Если текущий узел пуст, создаём новый
return Node(d)
if d < root.data: # Если значение меньше, идём в левое поддерево
root.left = insert(root.left, d)
elif d > root.data: # Если больше, идём в правое поддерево
root.right = insert(root.right, d)
return root # Возвращаем (возможно обновлённый) корень
def inorder(root):
# Симметричный обход для вывода значений по возрастанию
if root:
inorder(root.left) # Сначала левое поддерево
print(root.data, end=' ') # Потом текущий узел
inorder(root.right) # Потом правое поддерево
def search(root, k):
# Поиск узла с ключом k в дереве с корнем root
if not root or root.data == k: # Если найден узел или достигнут лист
return root
# Идем в левое или правое поддерево в зависимости от сравнения
return search(root.left, k) if k < root.data else search(root.right, k)
def minNode(n):
# Поиск узла с минимальным значением в дереве с корнем n
while n.left: # Идём как можно левее
n = n.left
return n
def delete(root, d):
# Удаление узла с значением d из дерева с корнем root
if not root: # Если дерево пустое, ничего не делать
return None
if d < root.data: # Если значение меньше текущего, удалить из левого поддерева
root.left = delete(root.left, d)
elif d > root.data: # Если больше, удалить из правого поддерева
root.right = delete(root.right, d)
else: # Найдён удаляемый узел
if not root.left: # Если нет левого потомка, вернуть правого (может быть None)
return root.right
if not root.right: # Если нет правого потомка, вернуть левого
return root.left
# Если есть оба потомка, найти минимальный узел в правом поддереве (inorder successor)
temp = minNode(root.right)
root.data = temp.data # Копируем значение преемника сюда
root.right = delete(root.right, temp.data) # Удаляем преемника справа
return root
# Пример использования
root = None
# Вставка элементов
for v in [50, 30, 20, 40, 70, 60, 80]:
root = insert(root, v)
inorder(root) # Вывод значений дерева в отсортированном порядке
print()
root = delete(root, 20) # Удаляем узел со значением 20
inorder(root)
print()
root = insert(root, 25) # Вставляем значение 25
inorder(root)
print()
# Поиск узла со значением 25 и вывод результата
print("Есть 25" if search(root, 25) else "Нет 25")