Обход дерева по порядку:Какое определение является правильным?

StackOverflow https://stackoverflow.com/questions/486039

Вопрос

У меня есть следующий текст из академического курса, который я прослушал некоторое время назад, о обходе inorder (они также называют это pancaking) бинарное дерево (не BST):

Обход дерева по порядку

Нарисуйте линию вокруг внешней стороны дерева .Начните слева от корня, и обойдите дерево снаружи, чтобы оказаться справа от корня.Держитесь как можно ближе к дереву, но не перелезайте через дерево.(Представьте себе дерево — его ветви и узлы — как сплошной барьер.) Порядок расположения узлов - это порядок, в котором эта линия проходит под ними.Если вы не уверены в том, когда вы переходите “под” узел, помните, что узел “слева ” всегда идет первым.

Вот использованный пример (немного отличающееся дерево от приведенного ниже)

tree 1

Однако, когда я выполняю поиск в Google, я получаю противоречивое определение.Например , в пример из Википедии:

Tree definition

Последовательность обхода по порядку:A, B, C, D, E, F, G, H, I (левый дочерний элемент, корневой узел, правый узел)

Но согласно (моему пониманию) определению № 1, это должно быть

A, B, D, C, E, F, G, I, H

Кто-нибудь может уточнить, какое определение является правильным? Возможно, они оба описывают разные методы обхода, но случайно используют одно и то же имя.Мне трудно поверить, что рецензируемый академический текст ошибочен, но я не могу быть уверен.

Это было полезно?

Решение

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

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

Другие советы

Забудьте об определениях, гораздо проще просто применить алгоритм:

void inOrderPrint(Node root)
{
  if (root.left != null) inOrderPrint(root.left);
  print(root.name);
  if (root.right != null) inOrderPrint(root.right);
}

Это всего лишь три строчки.Измените порядок предварительного и последующего заказа.

Если вы внимательно прочтете, то увидите, что в первом "определении" говорится о начале слева корня и что порядок узлов определяется тем, когда вы передаете под их.Итак B не является первым узлом, так как вы проходите его слева по пути к A, затем первый проход под A после чего вы поднимаетесь и проходите под B.Поэтому кажется, что оба определения дают один и тот же результат.

Я лично нашел эта лекция весьма полезно.

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

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

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

Правильный обход был бы:как можно дальше влево с конечными узлами (не корневыми узлами)

Левый Корень Правый

A B НУЛЕВОЙ

C D E

Ноль F G

H I НУЛЬ

F - это корень или левый, я не уверен

Я думаю, что первое двоичное дерево с корнем a это двоичное дерево, которое построено неправильно.

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

Но согласно (моему пониманию) определение #1, это должно быть

A, B, D, C, E, F, G, I, H

К сожалению, ваше понимание неверно.

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

Эй, по моему мнению, как упомянуто в wiki, правильная последовательность для обхода по порядку - left-root-right.

До A, B, C, D, E, F, я думаю, вы уже поняли.Теперь после root F следующим узлом является G, у которого есть не левый узел, а правый узел, так что согласно правилу (left-root-right) его null-g-right .Теперь I является правым узлом G, но у I есть левый узел, следовательно, обход был бы GHI .Это правильно.

Надеюсь, это поможет.

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

Правильный обход был бы:как можно дальше влево с конечными узлами (A), вернитесь к родительскому узлу (B), переместитесь вправо, но поскольку у D есть дочерний узел слева, вы снова перемещаетесь вниз (C), возвращаетесь к родительскому узлу C (D), к правому дочернему узлу D (E), возвращаетесь к корневому (F), перемещаетесь к правому листу (G), перемещаетесь к листу G, но поскольку у него есть левый конечный узел, перемещаетесь туда (H), возвращаетесь к родительскому (I).

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

структура данных пакета;

открытый класс BinaryTreeTraversal {

public static Node<Integer> node;

public static Node<Integer> sortedArrayToBST(int arr[], int start, int end) {
    if (start > end)
        return null;

    int mid = start + (end - start) / 2;
    Node<Integer> node = new Node<Integer>();
    node.setValue(arr[mid]);

    node.left = sortedArrayToBST(arr, start, mid - 1);
    node.right = sortedArrayToBST(arr, mid + 1, end);
    return node;
}

public static void main(String[] args) {

    int[] test = new int[] { 1, 2, 3, 4, 5, 6, 7 };
    Node<Integer> node = sortedArrayToBST(test, 0, test.length - 1);

    System.out.println("preOrderTraversal >> ");

    preOrderTraversal(node);

    System.out.println("");

    System.out.println("inOrderTraversal >> ");

    inOrderTraversal(node);

    System.out.println("");

    System.out.println("postOrderTraversal >> ");

    postOrderTraversal(node);

}

public static void preOrderTraversal(Node<Integer> node) {

    if (node != null) {

        System.out.print(" " + node.toString());
        preOrderTraversal(node.left);
        preOrderTraversal(node.right);
    }

}

public static void inOrderTraversal(Node<Integer> node) {

    if (node != null) {

        inOrderTraversal(node.left);
        System.out.print(" " + node.toString());
        inOrderTraversal(node.right);
    }

}

public static void postOrderTraversal(Node<Integer> node) {

    if (node != null) {

        postOrderTraversal(node.left);

        postOrderTraversal(node.right);

        System.out.print(" " + node.toString());
    }

}

}

структура данных пакета;

узел открытого класса {

E value = null;
Node<E> left;
Node<E> right;

public E getValue() {
    return value;
}

public void setValue(E value) {
    this.value = value;
}

public Node<E> getLeft() {
    return left;
}

public void setLeft(Node<E> left) {
    this.left = left;
}

public Node<E> getRight() {
    return right;
}

public void setRight(Node<E> right) {
    this.right = right;
}

@Override
public String toString() {
    return " " +value;
}

}

Предварительный заказ в обратном направлении >> 4 2 1 3 6 5 7 В обратном порядке >> 1 2 3 4 5 6 7 После обратного заказа >> 1 3 2 5 7 6 4

void
inorder (NODE root)
{
  if (root != NULL)
    {
      inorder (root->llink);
      printf ("%d\t", root->info);
      inorder (root->rlink);
    }
}

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

Это правильно для предварительного заказа, nt для inorder

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top