Обход дерева – центрированный (inorder), прямой (preorder) и обратный (postorder) (три основных способа обхода)

Алгоритм, Tree, Дерево

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

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

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

Начиная сверху, слева направо

1 -> 12 -> 9 -> 5 -> 6

Начиная снизу, слева направо

5 -> 6 -> 12 -> 9 -> 1

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

Вместо этого мы используем методы обхода, которые учитывают базовую структуру дерева, то есть

struct node {
    int data;
    struct node* left;
    struct node* right;
}

Узел структуры, на который указывают left (левый) и right (правый) , может иметь другие левые и правые дочерние элементы, поэтому мы должны рассматривать их как поддеревья, а не подузлы.

Согласно этой структуре каждое дерево представляет собой комбинацию

  • Узел, несущий данные
  • Два поддерева

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

В зависимости от порядка, в котором мы это делаем, может быть три типа обхода .

Центрированный тип обхода (Inorder traversal)

  1. Сначала посетите все узлы в левом поддереве
  2. Затем корневой узел
  3. Посетите все узлы в правом поддереве
inorder(root->left)
display(root->data)
inorder(root->right)

Прямой тип обхода (Preorder traversal)

  1. Посетите корневой узел
  2. Посетите все узлы в левом поддереве
  3. Посетите все узлы в правом поддереве
display(root->data)
preorder(root->left)
preorder(root->right)

Обратный тип обхода (Postorder traversal)

  1. посетить все узлы в левом поддереве
  2. посетить корневой узел
  3. посетить все узлы в правом поддереве
postorder(root->left)
postorder(root->right)
display(root->data)

Давайте визуализируем центрированный тип обхода (inorder traversal). Начнем с корневого узла.

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

Давайте поместим все это в стек, чтобы мы помнили.

Теперь перейдем к поддереву, указанному на вершине стека.

Опять же, мы следуем тому же правилу центрированного типа (inorder)

Left subtree -> root -> right subtree

Пройдя левое поддерево, мы остаемся с

Поскольку у узла "5" нет поддеревьев, мы печатаем его напрямую. После этого мы печатаем его родительский узел «12», а затем правый дочерний «6».

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

После прохождения всех элементов, центрированный тип обхода (inorder traversal) выглядит так:

5 -> 12 -> 6 -> 1 -> 9

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

Полный код для центрированного (inorder), прямого (preorder) и обратного (postorder) типа обхода на языке программирования C размещен ниже:

#include <stdio.h>
#include <stdlib.h>

struct node {
    int data;
    struct node* left;
    struct node* right;
};

void inorder(struct node* root){
    if(root == NULL) return;
    inorder(root->left);
    printf("%d ->", root->data);
    inorder(root->right);
}

void preorder(struct node* root){
    if(root == NULL) return;
    printf("%d ->", root->data);
    preorder(root->left);
    preorder(root->right);
}

void postorder(struct node* root) {
    if(root == NULL) return;
    postorder(root->left);
    postorder(root->right);
    printf("%d ->", root->data);
}


struct node* createNode(value){
    struct node* newNode = malloc(sizeof(struct node));
    newNode->data = value;
    newNode->left = NULL;
    newNode->right = NULL;

    return newNode;
}

struct node* insertLeft(struct node *root, int value) {
    root->left = createNode(value);
    return root->left;
} 


struct node* insertRight(struct node *root, int value){
    root->right = createNode(value);
    return root->right;
}


int main(){
    struct node* root = createNode(1);
    insertLeft(root, 12);
    insertRight(root, 9);

    insertLeft(root->left, 5);
    insertRight(root->left, 6);

    printf("Inorder traversal \n");
    inorder(root);

    printf("\nPreorder traversal \n");
    preorder(root);

    printf("\nPostorder traversal \n");
    postorder(root);
}

Вывод кода будет выглядеть так:

Inorder traversal                                                                                                                                                         
5 ->12 ->6 ->1 ->9 ->                                                                                                                                                     
Preorder traversal                                                                                                                                                        
1 ->12 ->5 ->6 ->9 ->                                                                                                                                                     
Postorder traversal                                                                                                                                                       
5 ->6 ->12 ->9 ->1 ->
Virtual hosting with 10 percent discount
Virtual hosting with 10 percent discount
EVILEG offers reliable hosting with a 10% discount for virtual hosting and 5% for VPS
Support the author Donate

Comments

Only authorized users can post comments.
Please, Log in or Sign up
D
Aug. 16, 2019, 12:58 p.m.
Damir

C++ - Тест 003. Условия и циклы

  • Result:92points,
  • Rating points8
D
Aug. 16, 2019, 12:46 p.m.
Damir

C++ - Test 005. Structures and Classes

  • Result:75points,
  • Rating points2
u
Aug. 14, 2019, 2:55 p.m.
unrealproro

C++ - Test 005. Structures and Classes

  • Result:83points,
  • Rating points4
Last comments
D
Aug. 17, 2019, 9:04 a.m.
Damir

github ChekableTView Правой групповая смена значения при перетаскивании левой как обычно.
Aug. 16, 2019, 1:03 p.m.
Evgenij Legotskoj

Потому, что в минуте 60 секунд
Aug. 16, 2019, 12:16 p.m.
Dmitrij

а почему делитель 60000, а не 1000?
g
Aug. 14, 2019, 1:27 a.m.
grig_p

Спасибо большое. Получилось
Aug. 13, 2019, 10:43 a.m.
Evgenij Legotskoj

Самая главная проблема в том, что у вас это константные переменные, и инициализируется они один единственный раз при запуске программы. Поэтому делать динамический перевод в таком случае у …
Now discuss on the forum
Aug. 17, 2019, 1:53 p.m.
Ruslan Polupan

Не очень понятен вопрос. База одна или их несколько?
Aug. 15, 2019, 3:19 a.m.
Mihailll

Плюсы и qml отличаются, с++ логичней
Aug. 14, 2019, 8:20 a.m.
Evgenij Legotskoj

Да это не столько баги QML, сколько поведение JavaScript, который используется в нём. Из-за отсутствия строгой типизации получаем некоторые проблемы с преобразованием типов. в итоге, на первый в…
Aug. 14, 2019, 2:33 a.m.
BlinCT

Ошибка найдена) недосмотрел.
Aug. 13, 2019, 3:52 a.m.
Evgenij Legotskoj

Бери остаток от деления #include <QCoreApplication>#include <QTime>#include <QDebug>int main(int argc, char *argv[]){ QCoreApplication a(argc, argv); QTime time…
Looking for a Job?
14,000.00 руб. - 40,000.00 руб.
Разработчик Qt
Annino, Moscow Oblast, Russia
5,000.00 руб. - 15,000.00 руб.
Дизайнер
Moskovskiy, Moscow, Russia
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

For registered users on the site there is a minimum amount of advertising

EVILEG
About
Services
Join us
© EVILEG 2015-2019
Recommend hosting TIMEWEB