B-Tree (Balanced Tree) — самобалансирующееся дерево поиска, в котором каждый узел может хранить несколько ключей и иметь несколько дочерних узлов. Разработано в 1970 году Рудольфом Байером и Эдом МакКрейтом для эффективной работы с дисковым хранилищем.
Для B-Tree порядка t (минимальная степень, t ≥ 2):
| Свойство | Значение |
|---|---|
| Минимум ключей в узле | t - 1 (кроме корня) |
| Максимум ключей в узле | 2t - 1 |
| Минимум дочерних узлов | t (для внутреннего узла) |
| Максимум дочерних узлов | 2t |
| Все листья | на одном уровне |
| Ключи в узле | отсортированы по возрастанию |
┌─────────────────────────────────────────────┐
│ P0 │ K1 │ P1 │ K2 │ P2 │ K3 │ P3 │ ... │ │
└─────────────────────────────────────────────┘
↑ ↑ ↑ ↑
указатель ключ указатель ключ
на детей на детей
P0 < K1 < поддерево P1 < K2 < ...≥ targetПоиск 16 в дереве выше:
Корень [10|20|30]: 16 < 20 → идём в P1
Узел [15|17]: 15 < 16 < 17 → идём в P1
Лист [16]: 16 == 16 ✓
Ключевое правило: нельзя вставлять в переполненный узел (2t-1 ключей).
Алгоритм (проактивное разбиение):
1. Спускаемся от корня к нужному листу
2. Если встречаем полный узел (2t-1 ключей) — разбиваем ДО входа в него
3. Вставляем ключ в лист
Разбиение (Split) узла:
До: Родитель[...] → Полный узел [K1 K2 K3 K4 K5] (t=3, max=5)
↑
медианный ключ K3
После: Родитель[... K3 ...]
↙ ↘
[K1 K2] [K4 K5]
Медиана поднимается в родителя, узел делится на два.
Три случая:
| Случай | Ситуация | Действие |
|---|---|---|
| 1 | Ключ в листе | Удалить напрямую |
| 2 | Ключ во внутреннем узле | Заменить на predecessor/successor из листа, удалить оттуда |
| 3 | Узел после удаления опустеет | Слияние (merge) или перераспределение с соседом |
Слияние (Merge):
Родитель [...K...] Родитель [...]
↙ ↘ → ↓
[A B] [D E] [A B K D E]
(бедный) (бедный) (слитый)
Перераспределение (Rotation):
Родитель [...K...] Родитель [...B...]
↙ ↘ → ↙ ↘
[A] [B C D] [A K] [C D]
(бедный) (богатый)
{
"title": { "text": "Сложность операций B-Tree" },
"tooltip": { "trigger": "axis" },
"legend": { "data": ["O(log n)", "O(n) — худший случай других структур"] },
"xAxis": {
"type": "category",
"data": ["1K", "10K", "100K", "1M", "10M", "100M"]
},
"yAxis": {
"type": "value",
"name": "Операций"
},
"series": [
{
"name": "O(log n)",
"type": "line",
"data": [10, 13, 17, 20, 23, 27],
"smooth": true,
"lineStyle": { "color": "#5cb85c", "width": 3 }
},
{
"name": "O(n) — худший случай других структур",
"type": "line",
"data": [1000, 10000, 100000, 1000000, 10000000, 100000000],
"smooth": true,
"lineStyle": { "color": "#d9534f", "width": 2, "type": "dashed" }
}
]
}
| Операция | Среднее | Худшее |
|---|---|---|
| Поиск | O(log n) | O(log n) |
| Вставка | O(log n) | O(log n) |
| Удаление | O(log n) | O(log n) |
| Обход | O(n) | O(n) |
Высота дерева: h = O(log_t n) — чем больше
t, тем ниже дерево
| B-Tree | B+Tree | |
|---|---|---|
| Данные хранятся | В любом узле | Только в листьях |
| Листья связаны | Нет | Да (linked list) |
| Range queries | Медленнее | Очень быстро |
| Применение | Файловые системы | Большинство СУБД |