2010-02-11 5 views
5

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

alt text

Я написал следующую программу.

package dsa.tree; 

import java.util.Stack; 

public class TracePath { 
    private Node n1; 

    public static void main(String args[]){ 
     TracePath nodeFinder = new TracePath(); 
     nodeFinder.find(); 
    } 

    public void find(){ 
     Tree t = getSampleTree(); 
     tracePath(t,n1); 
    } 

    private Tree getSampleTree() { 
     Tree bsTree = new BinarySearchTree(); 
     int randomData[] = {43,887,11,3,8,33,6,0,46,32,78,76,334,45}; 
     for(int i=0;i<randomData.length;i++){ 
      bsTree.add(randomData[i]); 
     } 
     n1 = bsTree.search(76); 
     return bsTree; 
    } 

    public void tracePath(Tree t, Node node){ 
     trace(t,node); 
    } 

    Stack<Node> mainStack = new Stack<Node>(); 

    public void trace(Tree t, Node node){ 
     trace(t.getRoot(),node); 
    } 

    private void trace(Node parent, Node node){ 
     mainStack.push(parent); 
     if(node.data == parent.data){ 
      for(Node iNode:mainStack){ 
       System.out.println(iNode.data); 
      } 
      return; 
     } 
     if(parent.left != null){ 
      trace(parent.left, node); 
     } 
     if(parent.right!=null){ 
      trace(parent.right, node); 
     } 
     mainStack.pop(); 
    } 
} 

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

Просьба сообщить.

ответ

5

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

private boolean trace(Node parent, Node node){ 
    mainStack.push(parent); 
    if(node.data == parent.data){ 
     for(Node iNode:mainStack){ 
      System.out.println(iNode.data); 
     } 
     return true; 
    } 
    if(parent.left != null){ 
     if (trace(parent.left, node)) return true; 
    } 
    if(parent.right!=null){ 
     if (trace(parent.right, node)) return true; 
    } 
    mainStack.pop(); 
    return false; 
} 
+0

Отлично !!! Большое спасибо. Теперь я испытал, как прекратить/выйти из рекурсивного метода. Еще раз спасибо! – bragboy

+0

Теперь, когда вы дали «решение» вместо подсказки домашней работы, я отредактирую свой ответ, чтобы показать, что я имел в виду. – rsp

+0

Решение опубликовано: http://www.technicalypto.com/2010/02/trace-path-of-binary-tree.html Спасибо. – bragboy

3

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

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

Edit: Если узел пути к корню желанное, простое логическое возвращение достаточно:

private boolean trace(Node parent, Node node) { 
    boolean found = (node.data == parent.data) 

    if (!found && parent.left != null) { 
     found = trace(parent.left, node); 
    } 
    if (!found && parent.right != null){ 
     found = trace(parent.right, node); 
    } 

    if (found) { 
     System.out.println(parent.data); 
    } 

    return found; 
} 

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

private boolean trace(Node parent, Node node, List path) { 
    boolean found = (node.data == parent.data) 

    if (!found && parent.left != null) { 
     found = trace(parent.left, node); 
    } 
    if (!found && parent.right != null){ 
     found = trace(parent.right, node); 
    } 

    if (found) { 
     path.add(0, parent); 
    } 

    return found; 
} 

в качестве альтернативы вы можете построить путь на обратном пути и вернуться в список.

private List trace(Node parent, Node node) { 
    List path = null; 

    if (null != node) { 
     if (node.data == parent.data) { 

      path = new ArrayList(); 
     } else { 
      path = trace(parent.left, node); 

      if (null == path) { 
       path = trace(parent.right, node); 
      } 
     } 
     if (null != path) { 
      path.add(0, parent); 
     } 
    } 
    return path; 
} 
+0

Спасибо за подсказки .. Мое сомнение заключается в том, как завершить эту программу? – bragboy

+0

Вы ошибаетесь, ему нужен стек. Если он избавится от него и просто распечатает, он напечатает лист, затем родитель листа, затем он родительский, вернется к корню. Он нуждается в обратном отпечатанном, поэтому Stack необходим для хранения пути. – Schmelter

+0

@Schmelter, я дал 2 возможных значения возврата, логическое значение, когда требуется узел для root, или список, который строится, когда узел встречается иначе. Стек, который получает все узлы, посещений алгоритмов не требуется. – rsp

0

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

1

Что-то вроде этого?

public Stack<Node> findPath(Node src, Node dest, Stack<Node> alreadyCollected) { 
    if (src == dest) 
     return alreadyCollected; 
    if (src.left == null && src.right == null) 
     return null; 
    if (src.left != null) { 
     Stack<Node> toTheLeft = new Stack<Node>(alreadyCollected); 
     toTheLeft.push(src.left); 
     Stack<Node> result = findPath(src.left, dest, toTheLeft); 
     if (result != null) 
      return result; 
    } 
    List<Node> toTheRight = new Stack<Node>(alreadyCollected); 
    return findPath(src.right, dest, toTheRight); 
} 
+0

Спасибо за ваш ответ. Я чувствую, что вы создаете слишком много нового Stack() внутри рекурсивного цикла. Выглядит дорого. – bragboy

+0

Я думаю, что вы правы ;-) – Hubert

1

Рекурсивная функция без использования стека. Рекурсия эквивалентна стеку techincally, и вам не нужно создавать стек при выполнении recusrion.

PS: Я пишу псевдокод. Перепишите его сами, чтобы скомпилировать его :)

bool trace(Node curr, Node n, Path path){ 
    if(curr == null) 
     return; 
    if(n == curr){ 
     path.insertAtEnd(curr); 
     return true; 
    } 

    if(trace(curr.left, n, path)){ 
     path.insertAtEnd(curr); 
     return true; 
    } 
    if(trace(curr.right, n, path)){ 
     path.insertAtEnd(curr); 
     return true; 
    } 
    return false 
} 
+0

Переменный путь - это просто массив и нет, где он используется как стек (LIFO). –

+0

Ваш код работает плавно !!!! Большое спасибо Niraj .. Да, стек выполняет дополнительную поп-операцию, которая не нужна, когда это можно сделать таким образом. – bragboy

+0

Просто FYI, преобразованный код выглядит частного булевой следа (Node Node, Curr н, Список путь) { \t если (ТОК == NULL) \t возвращение ложным; \t if (n == curr) { \t path.add (curr); \t return true; \t if (след (curr.left, n, path)) { \t путь.адд (curr); \t return true; \t} \t if (trace (curr.right, n, path)) { \t path.add (curr); \t return true; \t} \t return false; \t} – bragboy