2010-02-11 19 views
5

Próbuję prześledzić ścieżkę węzła w drzewie binarnym (a nie binarnym drzewie wyszukiwania). Biorąc pod uwagę węzeł, próbuję wydrukować wartości ścieżki z katalogu głównego.Potrzebujesz pomocy w powrocie z metody rekurencyjnej

alt text

Napisałem następujący program.

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(); 
    } 
} 

Dostaję poprawnie dane wyjściowe. Ale jego rodzaj bałaganu. Jeśli widzisz śledzenie metody (Węzeł, Węzeł), drukuję wartości, których nie powinienem robić. Chcę, aby metoda śledzenia została poprawnie ukończona. Przynajmniej powinienem zabić strukturę rekursywną na etapie, w którym napotykam warunek if.

Prosimy o radę.

Odpowiedz

5

Okej, musisz zabić rekursję, gdy znajdziesz swój węzeł. Wystarczająco proste. Zmień metodę śledzenia, aby zwrócić wartość boolowską informującą nas, czy węzeł został znaleziony. W ten sposób idziemy z powrotem do drzewa zaraz po znalezieniu węzła.

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

Doskonały !!! Dziękuję bardzo .. Teraz doświadczyłem, jak zakończyć/wyjść z metody rekurencyjnej .. Jeszcze raz dziękuję! – bragboy

+0

Teraz, gdy podałeś "rozwiązanie" zamiast wskazówki domowej, zmienię moją odpowiedź, aby pokazać, co mam na myśli. – rsp

+0

Rozwiązanie zamieszczone na stronie: http://www.technicalypto.com/2010/02/trace-path-of-binary-tree.html Dzięki. – bragboy

3

Zakładam, że to praca domowa, więc podam kilka wskazówek zamiast jakiegoś kodu.

  • metoda śladu nie rekurencyjny zejście, dlatego stos nie jest potrzebna - można zbudować strukturę ścieżki podczas powrotu z znalezionego węzła
  • jeśli metoda wykorzystuje logiczną lub listy wartości zwracanej, można drukować ścieżka podczas powrotu, lub zbudować listę z węzłami do wydrukowania po metodę wyszukiwania zwraca

Edit: Jeśli węzeł ścieżka do korzenia jest poszukiwany, prosta logiczna powrót wystarczy:

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; 
} 

Jeśli potrzebujesz ścieżkę od korzenia do węzła, można przekazać listę otrzymywać węzły w kolejności:

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; 
} 

alternatywnie można zbudować ścieżkę na drodze z powrotem i zwrócić w postaci listy.

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

Dzięki za podpowiedzi .. Mam wątpliwości, jak zakończyć ten program? – bragboy

+0

Mylisz się, on potrzebuje stosu. Jeśli się go pozbędzie i po prostu wydrukuje, wydrukuje liść, a następnie rodzica liścia, a następnie rodzica, z powrotem do korzeni. Potrzebuje odwrotności tego wydrukowanego, więc stos jest konieczny do przechowywania ścieżki. – Schmelter

+0

@Schmelter, dałem 2 możliwe wartości zwracane, boolean, gdy poszukiwany jest węzeł do roota lub listę, która jest budowana, gdy węzeł zostanie znaleziony w inny sposób. Stos, który odbiera wszystkie węzły, które odwiedza algorytm, nie jest potrzebny. – rsp

0

Zwraca wartość logiczną ze śledzenia i decyduje, czy kontynuować wyszukiwanie w oparciu o wartość zwracaną przez wywołanie rekursywne.

1

Coś takiego?

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

Dzięki za odpowiedź. Czuję, że tworzycie zbyt wiele nowych Stack() wewnątrz pętli rekursywnej. Wygląda dla mnie kosztownie. – bragboy

+0

Myślę, że masz rację ;-) – Hubert

1

Oto funkcja rekursywna bez użycia stosu. Rekursja jest równoważna stosowi w sposób techniczny i nie musisz używać stosu podczas robienia rekursji.

PS: Piszę pseudo kod. Przepisz sam, aby go skompilować :)

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

Ścieżka zmiennej jest po prostu tablicą i nie jest używana jako stos (LIFO). –

+0

Twój kod działa sprawnie !!!! Dziękuję bardzo Niraj .. Tak, stos robi dodatkową operację pop, która nie jest potrzebna, gdy można to zrobić w ten sposób. – bragboy

+0

Wystarczy FYI, kod przerobiona wygląda prywatnej logiczną śladu (Curr węzła Node N Lista path) { \t if (Curr == null) \t return false; \t jeśli (n == curr) { \t path.add (curr); \t return true; \t} \t jeśli (trace (curr.left, n, path)) { \t path.add (curr); \t return true; \t} \t jeśli (trace (curr.right, n, path)) { \t path.add (curr); \t return true; \t} \t return false; \t} – bragboy

Powiązane problemy