2013-03-04 7 views
0

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

Так у меня есть дерево, как это:

   A 
      / \ 
      B  C 
     / \/ \ 
      D E F  G 
     / \ 
     H  I 
    / \ 
    J  K 

и мой метод:

public BinaryTree preorderNext(BinaryTree t, BinaryTree v, BinaryTree prev) {  

    prev = t; 

    if(t.getLeft() != null) { 
     preorderNext(t.getLeft(), v, prev); 
    } 

    if(t.getRight() != null) { 
     preorderNext(t.getRight(), v, prev); 
    } 


    if(prev == v) { 
     return t; 
    } 

    return null; 
} 

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

Узел имеет две ссылки (один слева и другой справа), и нет ссылки на голову.

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

Но когда я запускаю тесты, он сообщает мне, что следующий узел предзаказа из A есть B, а следующий узел предварительного заказа из K выдает исключение null, но это должно быть я?

Любые идеи о том, где я ошибаюсь? Переменная prev должна содержать ссылку на последний посещенный узел, поэтому, если он равен узлу v (который является указанным узлом, чтобы вернуть узел после v), не должен ли я получить следующий узел?

+1

Можете изменить подпись функции? Гораздо проще иметь дело с 'root', чем с' t', 'v' и' prev'. Это связано с тем, что каждый ребенок дерева также является самим деревом. – arin

+0

Что это значит? t является корнем дерева, в которое я могу пройти. – tenkii

+0

Вы должны провести рекурсивный подход, а не передавать ранее полученную информацию методу; эта информация уже находится в стеке. Я отправлю ответ, чтобы объяснить мой подход для обхода порядка. – arin

ответ

0

Ниже приведена репликация выполнения preorder traversal.

public void preOrderTraversal(BinaryTree root){ 
    if(root == null) return; 

    System.out.println(root); 
    preOrderTraversal(root.getLeft()); 
    preOrderTraversal(root.getRight()); 
} 

Примечания:

  1. Я не уверен в своем подходе; почему вы возвращаете узел? В любом случае, когда root имеет значение null с таким подходом, вы можете вернуть «emptyNode» и обработать его с помощью оператора if.
  2. Как вы можете видеть, я имею дело только с root, с любым уровнем root изменений. Попытайтесь визуализировать это с помощью прогона, и вы поймете эту концепцию.
  3. Вам не хватает проверки нулевых узлов в начале (особенно для t).

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

Заключительное примечание относится к сложности выполнения этого подхода во время выполнения, поэтому я настоятельно рекомендую понять сложности во время выполнения для рекурсивных функций. Это поможет вам много в будущем. Проверьте this wikipedia article для повторных отношений.

+0

Я вижу, что вы пытаетесь сделать. Я возвращаю узел, потому что для получения следующего узла узла, поэтому следующий узел K в обход предварительного порядка - это я .. Вы сказали в комментарии к моему предыдущему сообщению, что мои узлы будут храниться в stack ... так как я могу получить J, когда я его открываю и получаю следующий узел после J? – tenkii

+0

Следующий узел 'K' будет' I' с управляющим потоком рекурсии. Я имею в виду, что после обработки 'K' (распечатайте его, выполните некоторую операцию на нем и т. Д.) Метод вернется к предыдущему вызову и будет иметь текущий' root' как 'I' (в вашем случае' t' будет 'I' я верю). Они будут обрабатываться стеком автоматически, вам не о чем беспокоиться. Посмотрите в Stack и как он используется с рекурсией, и вы поймете это. – arin

+0

Я понимаю, как работает стек с рекурсивными вызовами. Допустим, я просто иду по левому краю дерева. - Сначала проверьте, имеет ли A левый, он делает рекурсивный вызов на нем - тогда проверьте, есть ли у b левый, он делает так рекурсивный вызов на нем - тогда проверьте, что D имеет левый, он делает такой рекурсивный вызов это - тогда проверьте, что H имеет левый, он делает так рекурсивный вызов на нем – tenkii

0

Я не уверен, что выполнение этой задачи рекурсивно так просто.

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

public BinaryTree preOrderNext(BinaryTree toSearch) { 

    Stack<BinaryTree> openList = new Stack<BinaryTree>(); 

    openList.push(root); 

    while (openList.empty() == false) { 
     BinaryTree curr = openList.pop(); 

     if (curr.getRight() != null) 
      openList.push(curr.getRight()); 

     if (curr.getLeft() != null) 
      openList.push(curr.getLeft()); 

     if (curr.equals(toSearch) && openList.empty() == false){ 
      return openList.pop(); 
     } 
    } 
    return null; 
} 

Этот метод не тестировался, но должен работать.

+0

Вы не должны использовать идентификационный оператор '==', а не 'equals()' в своем последнем 'if' -запросе. – arin

+0

Вы правы. Починил это. – trylimits

0

Я предоставляю ответ, который работает в O(h) времени работы.

class Node { 
    public int key; 
    public Node l; 
    public Node r; 
    public Node p; 

    public Node(int key) { 
     this.key = key; 
     this.l = null; 
     this.r = null; 
     this.p = null; 
    } 
} 

public Node preorderNext(Node v) { 
    if (v.l != null) { 
     return v.l; 
    } else if (v.r != null) { 
     return v.r; 
    } else { 
     while (v.p != null) { 
      if (v == v.p.l) { 
       if (v.p.r != null) { 
        return v.p.r; 
       } else { 
        v = v.p; 
       } 
      } else { 
       if (v.p.p == null) { 
        return null; 
       } else if (v.p == v.p.p.l) { 
        if (v.p.p.r != null) { 
         return v.p.p.r; 
        } else { 
         v = v.p; 
        } 
       } else { 
        v = v.p; 
       } 
      } 
     } 
     return null; 
    } 
} 
+0

Это возвращает другой узел, правильный узел, для каждого вызова для предварительного обхода? Это действительно потрясающе. –