1#include <iostream>
2#include <algorithm>
3using namespace std;
4
5class Node { // Узел хранит значение и указатели на двух потомков
6private: // Приватные атрибуты: к ним обращаются только методы
7 int value;
8 Node* left;
9 Node* right;
10public:
11 Node(int v) : value(v), left(nullptr), right(nullptr) {}
12 int getValue() const { return value; }
13 Node* getLeft() const { return left; }
14 Node* getRight() const { return right; }
15 void setValue(int v) { value = v; }
16 void setLeft(Node* n) { left = n; }
17 void setRight(Node* n) { right = n; }
18};
19
20int height(Node* n) { // Высота: лист равен 1, пустое место (nullptr) равно 0
21 if (n == nullptr) return 0;
22 return 1 + max(height(n->getLeft()), height(n->getRight()));
23}
24
25int balanceFactor(Node* n) { // Коэффициент баланса: высота слева минус высота справа
26 return height(n->getLeft()) - height(n->getRight());
27}
28
29Node* rotateRight(Node* y) { // Простой поворот вправо: левый потомок x поднимается, y опускается
30 Node* x = y->getLeft();
31 y->setLeft(x->getRight());
32 x->setRight(y);
33 return x;
34}
35
36Node* rotateLeft(Node* x) { // Простой поворот влево: правый потомок y поднимается, x опускается
37 Node* y = x->getRight();
38 x->setRight(y->getLeft());
39 y->setLeft(x);
40 return y;
41}
42
43Node* rebalance(Node* n) { // Возвращает корень поддерева после балансировки
44 int bf = balanceFactor(n); // Вычисляется коэффициент баланса узла
45 if (bf > 1) { // Перекос влево. Если левый потомок не перекошен вправо, это случай LL
46 if (balanceFactor(n->getLeft()) < 0) // Левый потомок перекошен вправо: случай LR, сначала поворот влево
47 n->setLeft(rotateLeft(n->getLeft())); // Первый поворот случая LR
48 return rotateRight(n); // Поворот вправо: решает LL и вторую половину LR
49 }
50 if (bf < -1) { // Перекос вправо. Если правый потомок не перекошен влево, это случай RR
51 if (balanceFactor(n->getRight()) > 0) // Правый потомок перекошен влево: случай RL, сначала поворот вправо
52 n->setRight(rotateRight(n->getRight())); // Первый поворот случая RL
53 return rotateLeft(n); // Поворот влево: решает RR и вторую половину RL
54 }
55 return n; // Коэффициент от -1 до 1: поворот не нужен
56}
57
58Node* insert(Node* root, int v) { // Вставляет v в AVL-дерево и возвращает корень
59 if (root == nullptr) // Пустое место: новый узел помещается сюда
60 return new Node(v); // Создаёт новый узел
61 if (v < root->getValue()) // Меньшие значения идут влево, большие — вправо
62 root->setLeft(insert(root->getLeft(), v)); // Спускается в левое поддерево
63 else
64 root->setRight(insert(root->getRight(), v)); // Спускается в правое поддерево
65 return rebalance(root); // При возврате из каждого вызова проверяется баланс узла
66}
67
68int main() {
69 Node* root = buildTree(); // Показанное дерево, уже построенное
70 root = insert(root, v); // Первый вызов, из main
71 return 0; // Конец операции
72}