Дерева

Дерева є однією з ключових структур даних в алгоритмах і зустрічаються у широкому спектрі задач.

Дерево — це зв'язний, ациклічний, неорієнтований граф.

Граф G = (V, E) називається деревом, якщо він задовольняє такі властивості:

  • Зв'язність — між будь-якою парою вершин у графі існує шлях.

  • Ациклічність — граф не містить циклів.

У дереві з вершинами завжди рівно n - 1 ребро.

Основні властивості дерева

1. Зв'язність і унікальність шляхів

У дереві між будь-якою парою вершин існує єдиний шлях.

2. Кількість ребер

Для будь-якого дерева:

|E| = |V| - 1

3. Відсутність циклів

Додавання навіть одного ребра до дерева завжди створює цикл.

4. Корінь (для кореневого дерева)

Якщо одна вершина обрана як корінь, дерево стає орієнтованим від кореня до його нащадків. Це використовується у рекурсивних обходах та алгоритмах (, та ін.).

5. Піддерева

Будь-яка вершина разом зі своїми нащадками утворює піддерево. Піддерево саме є деревом.

6. Листя

Вершини без нащадків (у кореневому дереві) називаються листям.

7. Глибина та висота

  • Глибина вершини — це відстань від кореня до цієї вершини.

  • Висота дерева — це максимальна глибина серед усіх вершин.

8. Центр дерева

Центр — це вершина (або пара суміжних вершин), яка мінімізує максимальну відстань до всіх інших вершин.

Альтернативні визначення дерева

Наступні визначення дерева є еквівалентними і можуть використовуватись у різних контекстах:

  • Граф без циклів, який стає незв'язним при видаленні будь-якого ребра.

  • Зв'язний граф з вершинами і n - 1 ребрами.

  • Ациклічний граф з n - 1 ребрами та однією зв'язною компонентою.

Представлення дерев у коді

Залежно від задачі і типу дерева (загальне, бінарне, кореневе і т.д.), використовуються різні структури даних:

1. Списки суміжності

Цей підхід часто використовується у задачах зі спортивного програмування та при роботі з неорієнтованими чи орієнтованими деревами.

int n;
vector<vector<int>> tree(n); // дерево з n вершинами

// додавання ребра між вершинами u та v
tree[u].push_back(v);
tree[v].push_back(u); // для неорієнтованого дерева

2. Масив батьків

Дуже компактне представлення, особливо корисне, коли дерево вже побудовано.

vector<int> parent(n); // parent[i] — батько вершини i
// якщо i — корінь, parent[i] зазвичай встановлюється в -1 або 0

3. Вказівники / Структури (ООП стиль)

Зазвичай використовується для побудови бінарних дерев, тріє та інших структур, особливо в Python/Java/C++ з використанням об'єктно-орієнтованого програмування.

  • Бінарне дерево:

struct Node 
{
  int val;
  Node* left;
  Node* right;
  Node(int v) : val(v), left(nullptr), right(nullptr) {}
};
  • Загальне дерево:

struct Node 
{
  int val;
  vector<Node*> children;
  Node(int v) : val(v) {}
};

Список задач

18

Коментарі5