Печатать листовые узлы в двоичном дереве справа налево?

Я ищу ответ на это:

Найдите псевдокод вывода листовых узлов бинарного дерева справа налево.

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


person ronnie    schedule 10.05.2013    source источник


Ответы (9)


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

Самый простой способ реализовать это — использовать рекурсивную функцию.

void printLeafNodes(BinaryTreeNode* treePtr) {
  if(treePtr.leftChild == null && treePtr.rightChild == null) {
    //This is a leaf node; print its value
  } else {
    //Recurse on right subtree
    if(treePtr.rightChild != null) {
      printLeafNodes(treePtr.rightChild);
    }
    //Recurse on left subtree
    if(treePtr.leftChild != null) {
      printLeafNodes(treePtr.leftChild);
    }
  }
}

Эта страница очень полезна для визуализации решения: Обход дерева.

person Sildoreth    schedule 10.05.2013

void in(node* root){
if(root)
    {   
        if(!root->left && !root->right)
              cout<<root->data<<endl;
        in(root->left);
        in(root->right);
    } }

Вы можете сделать что-то вроде этого (код на C++).

Идея этого кода заключается в том, чтобы выполнить обход в обратном порядке/обход в обратном порядке и проверить, являются ли левые и правые дочерние элементы NULL или нет. Если это Null, это означает, что это конечный узел.

person SevenDante    schedule 14.08.2017

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

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

function processNode(parent) {
    if(parent.right = null AND parent.left = null)
        print parent.name
    if(parent.right <> null)
        processNode(parent.right)
    if(parent.left <> null)
        processNode(parent.left)
}

Тогда вы должны начать с:

processNode(topNode)
person Tombala    schedule 10.05.2013
comment
Этот код будет печатать нелистовые узлы и дважды печатать конечные узлы. - person Sildoreth; 10.05.2013
comment
Я вижу, как это было бы напечатано дважды. Фиксированный. - person Tombala; 10.05.2013
comment
большое спасибо, ребята! Я действительно ценю ваше время и усилия! - person ronnie; 10.05.2013

  1. Выполнять обход по порядку и добавлять в список посещенных узлов только конечные узлы.
  2. Вернуть список.

Or

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

person Rohit Sachan    schedule 11.01.2016

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

person user8066942    schedule 25.05.2017

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

void postOrder(Node* root)
{
if(root==NULL)
return;
postOrder(root->right);
postOrder(root->left);
if(root->left==NULL && root->right==NULL)
cout << root->data <<" ";
}
person Rajender Kumar    schedule 21.06.2017

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

void visit(Node node) {
     if(node.hasLeft()) {
         visit(node.getLeft());
     }
     handleValue(node.value); // print or whatever
     if(node.hasRight()) {
         visit(node.getRight());
     }
}

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

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

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

person slim    schedule 15.08.2017

код питона

def Reverse_print(self):
    if self.right:
        self.right.Reverse_print()
    print(self.data),
    if self.left:
        self.left.Reverse_print()

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

person mo.khashab    schedule 12.06.2018

Я знаю, что воскрешаю старую ветку, но думаю, что это может помочь другим, просматривающим эту ветку. Если вы говорите о вопросе интервью, я думаю, что рекурсивный ответ — это лишь малая часть ответа, и интервьюер также хотел бы услышать итеративный подход. Обход справа налево (печать) не является обычным обходом pre/post/inorder, описанным в вики. Основная идея здесь заключается в том, что вам нужно идти как можно дальше вправо и начинать печать сначала с крайнего правого узла, затем его родителя и только потом левого поддерева.

Рекурсивный:

printRightToLeft(Node root){
  if (root == null)
     return;

  // You can check root.right and root.left for null before calling the
  // printRightToLeft function to avoid pushing unneeded data to recursion
  // call stack.

  printRightToLeft(root.right);
  if (root.right == null && root.left == null)
     print(root);
  printRightToLeft(root.left);
}

Итеративный:

printRightToLeft(Node root){
  if (root == null)
    return;

  Stack s = new Stack();
  s.push(root);

  while(!s.isEmpty()){
    Node n = s.top();

    if (n.right != null && !n.visited){
      s.push(n.right);
      n.visited = true;
    } else {
      s.pop();

      if (n.right == null && n.left == null)
         print(n);

      if (n.left != null)
         s.push(n.left);
    }
}
person MikeL    schedule 17.05.2013
comment
Похоже, вы неправильно поняли вопрос. Предполагается, что только листовые узлы должны быть напечатаны. - person Sildoreth; 27.04.2017
comment
@Sildoreth, вы абсолютно правы насчет непонимания части печати, и это можно легко исправить, но моя главная мысль заключалась в том, что для подобных вопросов на собеседовании всегда полезно упоминать не только рекурсивное решение, но и итерируемое тоже один (и наоборот) - person MikeL; 27.04.2017
comment
Рекурсивному решению не нужна Node.visited - почему нужна версия Stack? - person slim; 15.08.2017
comment
Итеративное решение нуждается в индикации посещений для узла, так что, когда вы возвращаете узел из стека, который вы уже посетили и из которого пошли направо, вы не пойдете снова направо, а пойдете по левому пути. Рекурсивное решение в этом не нуждается, поскольку в каждом узле оно разбивает рекурсию на правое крыло и левое крыло, не возвращаясь к узлу, поэтому указание не требуется. - person MikeL; 16.08.2017
comment
Есть и другие способы добиться этого, без добавления поля в Node и без изменения алгоритмом Nodes по ходу дела. Один из вариантов — собрать стек из Object, поместить в стек String или Node и решить, что делать, исходя из instanceof. Другой способ — создать класс Task и использовать Stack<Task>. - person slim; 21.08.2017