Деревья в C++

ДеревьяДо этой статьи мы рассматривали линейную структуру данных как статической, так и динамической природы. Теперь мы перейдем к нелинейной структуре данных. Первая структура данных в этой категории — “Деревья”.

Деревья — это нелинейные иерархические структуры данных. Дерево — это набор узлов, соединенных друг с другом с помощью “ребер”, которые либо направлены, либо неориентированы. Один из узлов обозначается как “корневой узел”, а остальные узлы называются дочерними узлами или конечными узлами корневого узла.

В общем, у каждого узла может быть сколько угодно дочерних узлов, но только один родительский узел.

Узлы дерева либо находятся на одном уровне, называемые сестринскими узлами, либо могут иметь отношения родитель-потомок. Узлы с одним и тем же родителем являются родственными узлами.

Ниже приведен пример дерева с его различными частями:

Пример дерева

Давайте пройдемся по определениям некоторых основных терминов, которые мы используем для обозначения деревьев:

Корневой узел: это самый верхний узел в древовидной иерархии. На приведенной выше схеме узел A является корневым узлом. Обратите внимание, что корневой узел не имеет никакого родительского узла.

Конечный узел: это нижний узел в древовидной иерархии. Конечные узлы — это узлы, у которых нет дочерних узлов. Они также называются внешними узлами. Узлы E, F, G, H и C в приведенном выше дереве являются конечными узлами.

Поддерево: поддерево представляет различных потомков узла, когда корень не равен null. Дерево обычно состоит из корневого узла и одного или нескольких поддеревьев. На приведенной выше схеме (B-E, B-F) и (D-G, D-H) являются поддеревьями.

Родительский узел: любой узел, кроме корневого узла, который имеет дочерний узел.

Узел-предок: это любой узел-предшественник на пути от корня к этому узлу. Обратите внимание, что у корня нет предков. На приведенной выше схеме A и B являются предками E.

Ключ: он представляет значение узла.

Уровень: представляет поколение узла. Корневой узел всегда находится на уровне 1. Дочерние узлы корня находятся на уровне 2, внуки корня находятся на уровне 3 и так далее. В общем случае каждый узел находится на уровне выше, чем его родительский узел.

Читать также:  Аргументы командной строки в C++

Путь: путь представляет собой последовательность последовательных ребер. На приведенной выше диаграмме путь к E равен A=>B->E.

Степень: степень узла указывает количество дочерних элементов, которые имеет узел. На приведенной выше схеме степень B и D равна 2 каждая, тогда как степень C равна 0.

Типы деревьев C++

Древовидная структура данных может быть классифицирована на следующие подтипы, как показано на схеме ниже:

Древовидная структура данных

1) Общее дерево

Общее дерево — это базовое представление дерева. У него есть узел и один или несколько дочерних узлов. Узел верхнего уровня, то есть корневой узел, присутствует на уровне 1, а все остальные узлы могут присутствовать на разных уровнях.

Общее дерево показано на схеме ниже:

Общее дерево

Как показано на схеме выше, общее дерево может содержать любое количество поддеревьев. Узлы B, C и D присутствуют на уровне 2 и являются родственными узлами. Аналогично, узлы E, F, G и H также являются родственными узлами.

Узлы, присутствующие на разных уровнях, могут демонстрировать отношения родитель-потомок. На приведенной выше схеме узлы B, C и D являются дочерними элементами A. Узлы E и F являются дочерними элементами B, тогда как узлы G и H являются дочерними элементами D.

Общее дерево продемонстрировано ниже с использованием реализации C++:

Вывод данных:

Общее созданное дерево выглядит следующим образом:
10
/ \
20 30
/
40

2) Леса

Всякий раз, когда мы удаляем корневой узел из дерева, а ребра соединяют элементы следующего уровня и корень, мы получаем непересекающиеся наборы деревьев, т.е. целый лес деревьев, как показано ниже:

Целый лес деревьев

На приведенной выше схеме мы получили два леса, удалив корневой узел A и три ребра, которые соединяли корневой узел с узлами B, C и D.

3) Бинарное дерево

Древовидная структура данных, в которой каждый узел имеет не более двух дочерних узлов, называется бинарным или двоичным деревом. Двоичное дерево является наиболее популярной древовидной структурой данных и используется в ряде применений, таких как вычисление выражений, базы данных и т.д.

Читать также:  Функции преобразования символов в С++

На следующей схеме показано бинарное дерево:

На приведенной выше схеме видно, что узлы A, B и D имеют по два дочерних элемента каждый. Бинарное дерево, в котором каждый узел имеет ровно ноль или два дочерних элемента, называется полным бинарным деревом. В этом дереве нет узлов, у которых есть дочерний элемент.

Полное бинарное дерево имеет полностью заполненное двоичное дерево, за исключением самого низкого уровня, который заполняется слева направо. Бинарное дерево, показанное выше, является полным двоичным деревом.

Ниже приведена простая программа для демонстрации бинарного дерева. Обратите внимание, что результатом дерева является последовательность обхода входного дерева по порядку:

Вывод данных:

Создано бинарное дерево:
5 10 15 20 30 40 45

4) Бинарное дерево поиска

Упорядоченное бинарное дерево называется двоичным или бинарным деревом поиска. В двоичном дереве поиска узлы слева меньше корневого узла, в то время как узлы справа больше или равны корневому узлу.

Пример бинарного дерева поиска показан ниже:

Пример бинарного дерева поиска

На приведенной выше схеме видно, что все левые узлы меньше 20, что является корневым элементом. С другой стороны, правые узлы больше корневого узла. Бинарное дерево поиска используется в методах поиска и сортировки.

5) Дерево выражений

Бинарное дерево, которое используется для вычисления простых арифметических выражений, называется деревом выражений.

Структура простого дерева выражений показано ниже:

Структура простого дерева выражений

В приведенном выше примере дерева выражений мы представляем выражение (a + b) / (a-b). Как показано на схеме выше, нелистовые узлы дерева представляют операторы выражения, а листовые узлы представляют операнды.

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

Методы обхода дерева

Линейные структуры данных, такие как массивы, связанные списки, стеки, очереди и т.д., все эти структуры данных имеют общую технику обхода, которая пересекает структуру только одним способом, т.е. линейно.

Но в случае деревьев есть разные методы обхода, перечисленные ниже:

1) По порядку: в этом методе обхода мы сначала проходим левое поддерево, пока в левом поддереве не останется больше узлов. После этого мы посещаем корневой узел, а затем переходим к обходу правого поддерева, пока в правом поддереве не останется больше узлов для обхода. Таким образом, порядок обхода по порядку — left-> root-> right .

Читать также:  Пространства имен в С++

2) Предварительный заказ: для метода обхода предварительного заказа мы сначала обрабатываем корневой узел, затем проходим все левое поддерево и, наконец, проходим правое поддерево. Следовательно, порядок обхода предварительного заказа — root-> left-> right .

3) После порядка: в технике обхода после порядка мы проходим левое поддерево, затем правое поддерево и, наконец, корневой узел. Порядок обхода для метода после порядка — это left->right->root .

Если n — корневой узел, а ‘l’ и ’r’ — левый и правый узлы дерева соответственно, то алгоритмы обхода дерева следующие:

Алгоритм по порядку (lnr):

  1. Пройти по левому поддереву, используя inOrder(левое поддерево).
  2. Перейти к корневому узлу (n).
  3. Пройти по правому поддереву, используя inOrder(правое поддерево).

Алгоритм предварительного заказа (nlr):

  1. Перейти к корневому узлу (n).
  2. Пройти по левому поддереву, используя предварительный заказ (левое поддерево).
  3. Пройти по правому поддереву, используя предварительный заказ (правое поддерево).

Алгоритм после порядка (lrn):

  1. Пройти по левому поддереву, используя postOrder(левое поддерево).
  2. Пройти по правому поддереву, используя postOrder(правое поддерево).
  3. Перейти к корневому узлу (n).

Из приведенных выше алгоритмов методов обхода мы можем видеть, что методы могут быть применены к данному дереву рекурсивным образом для получения желаемого результата.

Рассмотрим следующее дерево:

Следующее дерево

Используя вышеупомянутые методы обхода, последовательность обхода для вышеупомянутого дерева приведена ниже:

Порядок обхода: 2 3 5 6 10
Предварительный обход: 6 3 2 5 10
Обход по порядку: 2 5 3 10 6

Итог

Деревья — это нелинейная иерархическая структура данных, которая применяется в области программного обеспечения.

В отличие от линейных структур данных, которые имеют только один способ обхода списка, мы можем перемещаться по деревьям различными способами.

В следующей статье мы поговорим о бинарной древовидной структуре данных в C++.

С Уважением, МониторБанк

Добавить комментарий