2016-10-22 6 views
1

Ich habe eine Template-BST-Klasse erstellt und ich habe GetEnumerator implementiert, aber ich bin wirklich nicht zufrieden mit dem, was getan wurde.Ausbeute in Rekursion bst

so vor allem fühlte ich inneren Besuch eine Hilfsfunktion

private IEnumerable<Node<T>> innerVisit(Node<T> root) 
    { 
     if(root== null) 
     yield break; 

     if (root.Left != null) 
     { 
      var l = innerVisit(root.Left); 
      foreach (var item in l) 
       yield return item; 
     } 


     yield return root; 

     if (root.Right != null) 
     { 
      var r = innerVisit(root.Right); 
      foreach (var item in r) 
       yield return item; 
     } 


    } 

brauchte ich konnte wirklich die sie wiederholenden Code nicht mögen, aber keine richtige Lösung, um es , klar die Schleife zu wiederholen ist unrein finden, aber auch Ich habe das Gefühl, dass es unter einer Funktion, die in diese hineinspringen würde, zu begraben wäre, gelinde gesagt eine schlechte Praxis zu sein. Irgendwelche Vorschläge, wie man das richtig macht?

auch die Umsetzung vervollständigen ich geschrieben habe

 public IEnumerator<Node<T>> GetEnumerator() 
    { 

     var res = innerVisit(_root); 

     foreach (var item in res) 
      yield return item; 

    } 

aber auch das fühlt sich schlecht und eher ein Hack sicherzustellen, dass es innerhalb foreach-Schleife arbeiten und usw.

Antwort

2

ich nicht Ich denke, Sie können Ihr Problem lösen, ohne die gleichen Operationen wie Sie zu wiederholen, aber ich denke, Sie können es klarer machen, es ist Teil der Anforderungen, ein IEumerable zurückzugeben und wenn Sie es auf rekursive Weise tun möchten kann nicht verhindern, dass die Yield-Operationen wiederaufgenommen werden (aber Sie müssen nicht alle selbst schreiben, System.LINQ hilft uns dabei).
Wir können die Foreach und die Rendite mit Enumerable.Concat Methode ersetzen, damit wir die linke InnerVisit IEnumerable, IEnumerable, die wir für den Knoten selbst erstellen (ein Array mit 1 Element des aktuellen Knotens) und die rechte InnerVisit erstellen können IEnumerable:

private IEnumerable<Node<T>> InnerVisit(Node<T> node) 
{ 
    if(node == null) 
    {   
     return Enumerable.Empty<Node<T>>; 
    } 
    return InnerVisit(node.Left).Concat(new[] { node }).Concat(InnerVisit(node.Right)); 
} 

Beachten Sie, dass es keine Notwendigkeit, zu überprüfen, ob links oder rechts null ist, bevor Sie die rekursive Methode aufrufen, weil sie es später im inneren Ruf überprüfen wird, wenn es null ist, werden wir eine Enumerable.Empty<Node<T>> zurückkehren statt die Ausbeute zu brechen, wie Sie es getan haben.

Wir können auch GetEnumerator vereinfachen, indem GetEnumerator direkt auf das Ergebnis der Wurzel InnerVisit, so etwas wie dies Aufruf:

public IEnumerator<Node<T>> GetEnumerator() 
{ 
    return InnerVisit(_root).GetEnumerator(); 
} 
+0

Diese effektiv den gleichen Code wie der OP schrieb, gerade jetzt ein Einzeiler. Sie haben die Bedenken des OP nicht angesprochen, sondern nur dargelegt, was eigentlich eine andere Syntax ist, um das zu tun, was sie zuerst getan haben. – Enigmativity

+0

"Ich mag den Wiederholungscode wirklich nicht, konnte aber keine richtige Lösung dafür finden", dieser Code wiederholt nicht die gesamte Ertragsrückgabe und die foreach-Schleifen. Er bat nicht um einen anderen Algorithmus, er wollte einfach nicht den gleichen Foreach- und Yield-Code überall wiederholen. – YuvShap

+0

Jeder Aufruf von 'InnerVisit' ruft effektiv 'Ausbeute' auf, wenn es Elemente sind - es tut so oft wie der OP-Code. Und du nennst 'InnerVisit' auf der linken Seite und' InnerVisit' auf der rechten Seite - das ist Code wiederholt. Dies ist effektiv der gleiche Code wie das OP. Sie sollten versuchen zu erklären, wie Ihre Lösung anders ist. – Enigmativity