Vielen Dank für alle Vorschläge, aber jeder schlägt Baum- / Netzwerkdurchquerungen vor. Thesen sind im Wesentlichen alle Beispiele für Depth-First-Search (oder BFS, denke ich). Ich suchte nach anderen gut motivierten Algorithmen / Problemen.
Redfood
10
Ich mag diese Frage! "Erzählen Sie mir alle Verwendungen von Technik X, AUSSER die hauptsächliche praktische Verwendung von Technik X"
Justin Standard
1
Ich benutze die ganze Zeit Rekursion, aber normalerweise für mathematische und grafische Dinge. Ich versuche nach Beispielen für eine Rekursion zu suchen, die für Nicht-Programmierer von Bedeutung sind.
Redfood
6
Wählen Sie Ihre eigenen Abenteuerromane! Ich möchte das Ganze lesen, und Rekursion ist der beste Weg, dies zu tun.
Andres
In der realen Welt gibt es keine Rekursion. Rekursion ist eine mathematische Abstraktion. Sie können viele Dinge mithilfe der Rekursion modellieren. In diesem Sinne ist Fibonacci absolut real, da es einige reale Probleme gibt, die auf diese Weise modelliert werden können. Wenn Sie denken, dass Fibonacci keine reale Welt ist, dann würde ich behaupten, dass alle anderen Beispiele ebenfalls Abstraktionen sind, keine realen Beispiele.
Zane
Antworten:
40
Es gibt hier viele mathematische Beispiele, aber Sie wollten ein Beispiel aus der realen Welt. Mit ein wenig Nachdenken ist dies möglicherweise das Beste, was ich anbieten kann:
Sie finden eine Person, die sich eine bestimmte ansteckende Infektion zugezogen hat, die nicht tödlich ist und sich schnell selbst behebt (Typ A), mit Ausnahme von einer von fünf Personen (wir nennen diese Typ B), die dauerhaft damit infiziert sind und keine aufweisen Symptome und wirkt lediglich als Spreader.
Dies erzeugt ziemlich nervige Verwüstungswellen, wenn Typ B jemals eine Vielzahl von Typ A infiziert.
Ihre Aufgabe ist es, alle Typ B aufzuspüren und zu immunisieren, um das Rückgrat der Krankheit zu stoppen. Leider können Sie nicht allen ein landesweites Heilmittel verabreichen, da die Menschen, die Typ As sind, auch tödlich allergisch gegen das Heilmittel sind, das für Typ B wirkt.
Die Art und Weise, wie Sie dies tun würden, wäre eine soziale Entdeckung, wenn eine infizierte Person (Typ A) in der letzten Woche alle ihre Kontakte auswählt und jeden Kontakt auf einem Haufen markiert. Wenn Sie testen, ob eine Person infiziert ist, fügen Sie sie der Warteschlange "Follow-up" hinzu. Wenn eine Person vom Typ B ist, fügen Sie sie dem "Follow-up" am Kopf hinzu (weil Sie dies schnell stoppen möchten).
Wählen Sie nach der Verarbeitung einer bestimmten Person die Person an der Vorderseite der Warteschlange aus und wenden Sie bei Bedarf eine Impfung an. Holen Sie sich alle zuvor nicht besuchten Kontakte und testen Sie, ob sie infiziert sind.
Wiederholen Sie diesen Vorgang, bis die Warteschlange infizierter Personen 0 wird, und warten Sie dann auf einen weiteren Ausbruch.
(Ok, dies ist ein bisschen iterativ, aber es ist eine iterative Methode zur Lösung eines rekursiven Problems. In diesem Fall wird die erste Durchquerung einer Bevölkerungsbasis versucht, wahrscheinliche Wege zu Problemen zu finden. Außerdem sind iterative Lösungen häufig schneller und effektiver und ich entferne zwanghaft die Rekursion überall so sehr, dass sie instinktiv wird. .... verdammt!)
Vielen Dank - dies ist immer noch eine Grafikdurchquerung, aber es ist gut motiviert und für Nicht-Programmierer sinnvoll.
Redfood
Ich glaube, Patient 0 zu finden wäre ein besseres Beispiel. Bestimmen Sie alle Wechselwirkungen, die eine Infektion verursacht haben könnten. Wiederholen Sie dies für alle Beteiligten, die zum Zeitpunkt der Interaktion ansteckend waren, bis keine ansteckenden Personen mehr gefunden wurden
Wie ist das rekursiv? Klar, es ist hübsch. Aber rekursiv? Ein fraktaler Kohl hätte gut funktioniert, aber ich sehe keine Selbstähnlichkeiten in dieser Blume.
Clément
1
Nun, es ist ein bisschen nervös, aber es ist ein Beispiel für Phyllotaxis, das mit der Fibonacci-Sequenz beschrieben werden kann, die üblicherweise durch Rekursion implementiert wird.
Hans Sjunnesson
1
"üblicherweise durch Rekursion implementiert" bedeutet nicht unbedingt, dass die Blume dies tut. Vielleicht tut es das; Ich bin nicht genug Molekularbiologe, um es zu wissen, aber ohne eine Erklärung darüber, wie es funktioniert, sehe ich dies nicht als besonders hilfreich an. Downvoting. Wenn Sie eine Beschreibung hinzufügen möchten (unabhängig davon, ob sie biologisch korrekt ist oder nicht, kann dies zu Erkenntnissen führen), werde ich die Abstimmung gerne überdenken.
Lindes
65
Wie wäre es mit einer Verzeichnisstruktur im Dateisystem? Rekursives Suchen von Dateien, Löschen von Dateien, Erstellen von Verzeichnissen usw.
Hier ist eine Java-Implementierung, die den Inhalt eines Verzeichnisses und seiner Unterverzeichnisse rekursiv druckt.
import java.io.File;publicclassDirectoryContentAnalyserOneimplementsDirectoryContentAnalyser{privatestaticStringBuilder indentation =newStringBuilder();publicstaticvoid main (String args []){// Here you pass the path to the directory to be scanned
getDirectoryContent("C:\\DirOne\\DirTwo\\AndSoOn");}privatestaticvoid getDirectoryContent(String filePath){File currentDirOrFile =newFile(filePath);if(!currentDirOrFile.exists()){return;}elseif( currentDirOrFile.isFile()){System.out.println(indentation + currentDirOrFile.getName());return;}else{System.out.println("\n"+ indentation +"|_"+currentDirOrFile.getName());
indentation.append(" ");for(String currentFileOrDirName : currentDirOrFile.list()){
getPrivateDirectoryContent(currentDirOrFile +"\\"+ currentFileOrDirName);}if(indentation.length()-3>3){
indentation.delete(indentation.length()-3, indentation.length());}}}}
Matt Dillards Beispiel ist gut. Im Allgemeinen kann jedes Gehen eines Baumes im Allgemeinen sehr einfach durch Rekursion gehandhabt werden. Zum Beispiel das Kompilieren von Analysebäumen, das Gehen über XML oder HTML usw.
Ich finde dieses "Kompilieren von Analysebäumen" eine vernünftige Antwort, die Bäume betrifft, aber immer noch kein Suchproblem darstellt, wie es der Fragesteller wünscht. Es könnte auf einen allgemeinen Begriff der Zusammenstellung oder Interpretation einer Sprache verallgemeinert werden. Es könnte auch sein, eine natürliche Sprache, beispielsweise Englisch, zu "interpretieren" (zu verstehen, zu hören).
Ein State Array und ein Low können dies beschleunigen.
BCS
13
Rekursion ist immer dann angebracht, wenn ein Problem gelöst werden kann, indem es in Unterprobleme unterteilt wird, die denselben Algorithmus zur Lösung verwenden können. Algorithmen für Bäume und sortierte Listen passen natürlich zusammen. Viele Probleme in der Computergeometrie (und in 3D-Spielen) können rekursiv mithilfe von BSP-Bäumen ( Binary Space Partitioning ), fetten Unterteilungen oder anderen Methoden zur Aufteilung der Welt in Unterteile gelöst werden .
Rekursion ist auch angebracht, wenn Sie versuchen, die Richtigkeit eines Algorithmus zu gewährleisten. Bei einer Funktion, die unveränderliche Eingaben akzeptiert und ein Ergebnis zurückgibt, das eine Kombination aus rekursiven und nicht rekursiven Aufrufen der Eingaben darstellt, ist es normalerweise einfach, mithilfe mathematischer Induktion zu beweisen, dass die Funktion korrekt ist (oder nicht). Es ist oft schwierig, dies mit einer iterativen Funktion oder mit Eingaben zu tun, die mutieren können. Dies kann nützlich sein, wenn Sie sich mit Finanzberechnungen und anderen Anwendungen befassen, bei denen die Korrektheit sehr wichtig ist.
Sicherlich verwenden viele Compiler die Rekursion stark. Computersprachen sind von Natur aus rekursiv (dh Sie können if-Anweisungen in andere if-Anweisungen usw. einbetten).
Eingebettet, wenn Anweisungen nicht rekursiv sind.
John Meagher
Das Parsen erfordert jedoch eine Rekursion, John.
Apocalisp
2
John, die Tatsache, dass Sie if-Anweisungen verschachteln können, bedeutet, dass die Sprachdefinition (und wahrscheinlich der Sprachparser) rekursiv ist.
Derek Park
Rekursiver Abstieg ist eine der einfachsten Möglichkeiten, einen Compiler von Hand zu codieren. Nicht so einfach wie die Verwendung eines Tools wie yacc, aber einfacher zu verstehen, wie es funktioniert. Die gesamten tabellengesteuerten Zustandsautomaten können erklärt werden, sind jedoch normalerweise Black Boxes.
Eclipse
Die Antwort von Cody Brocious, in der das "Kompilieren von Analysebäumen" erwähnt wurde, wies ebenfalls auf diesen Bereich hin: Sprachanalyse / Interpretation / Kompilierung.
imz - Ivan Zakharyaschev
9
Deaktivieren / Festlegen der schreibgeschützten Steuerung für alle untergeordneten Steuerelemente in einem Containersteuerelement. Ich musste dies tun, weil einige der Kinderkontrollen selbst Container waren.
public static void SetReadOnly(Control ctrl, bool readOnly)
{
//set the control read only
SetControlReadOnly(ctrl, readOnly);
if (ctrl.Controls != null && ctrl.Controls.Count > 0)
{
//recursively loop through all child controls
foreach (Control c in ctrl.Controls)
SetReadOnly(c, readOnly);
}
}
Menschen sortieren häufig Stapel von Dokumenten mit einer rekursiven Methode. Stellen Sie sich zum Beispiel vor, Sie sortieren 100 Dokumente mit Namen. Legen Sie die Dokumente zuerst nach dem ersten Buchstaben in Stapel und sortieren Sie dann jeden Stapel.
Das Nachschlagen von Wörtern im Wörterbuch wird häufig durch eine rekursive Binärsuchtechnik durchgeführt.
In Organisationen erteilen Chefs häufig Abteilungsleiter, die wiederum den Managern Befehle erteilen, und so weiter.
Parser und Compiler können in einer rekursiven Abstiegsmethode geschrieben werden. Nicht der beste Weg, dies zu tun, da Tools wie lex / yacc schnellere und effizientere Parser generieren, aber konzeptionell einfach und leicht zu implementieren sind, sodass sie weiterhin üblich sind.
Die Rekursion wird auf Probleme (Situationen) angewendet, in denen Sie sie in kleinere Teile aufteilen (reduzieren) können und jedes Teil dem ursprünglichen Problem ähnelt.
Gute Beispiele dafür, wo Dinge, die kleinere Teile enthalten, die sich selbst ähnlich sind, sind:
Baumstruktur (ein Ast ist wie ein Baum)
Listen (Teil einer Liste ist immer noch eine Liste)
Behälter (russische Puppen)
Sequenzen (ein Teil einer Sequenz sieht aus wie der nächste)
Gruppen von Objekten (eine Untergruppe ist immer noch eine Gruppe von Objekten)
Rekursion ist eine Technik, um das Problem in immer kleinere Teile zu zerlegen, bis eines dieser Teile klein genug wird, um ein Kinderspiel zu sein. Nachdem Sie sie aufgelöst haben, müssen Sie die Ergebnisse natürlich wieder in der richtigen Reihenfolge "zusammennähen", um eine vollständige Lösung Ihres ursprünglichen Problems zu erhalten.
Einige rekursive Sortieralgorithmen, Tree-Walking-Algorithmen, Map / Reduce-Algorithmen, Divide-and-Conquer sind Beispiele für diese Technik.
In der Computerprogrammierung verfügen die meisten stapelbasierten Call-Return-Sprachen bereits über die für die Rekursion integrierten Funktionen:
Zerlegen Sie das Problem in kleinere Teile ==> Rufen Sie sich selbst für eine kleinere Teilmenge der Originaldaten auf.
Verfolgen Sie, wie die Teile aufgeteilt sind ==> Aufrufstapel,
nähen Sie die Ergebnisse zurück ==> stapelbasierte Rückgabe
Einige gute Beispiele für Rekursionen finden sich in funktionalen Programmiersprachen . In funktionalen Programmiersprachen ( Erlang , Haskell , ML / OCaml / F # usw.) ist es sehr häufig, dass bei der Listenverarbeitung eine Rekursion verwendet wird.
Beim Umgang mit Listen in typischen imperativen OOP-Sprachen werden Listen häufig als verknüpfte Listen implementiert ([item1 -> item2 -> item3 -> item4]). In einigen funktionalen Programmiersprachen werden Listen selbst jedoch rekursiv implementiert, wobei der "Kopf" der Liste auf das erste Element in der Liste und das "Ende" auf eine Liste zeigt, die den Rest der Elemente enthält ( [item1 -> [item2 -> [item3 -> [item4 -> []]]]). Es ist meiner Meinung nach ziemlich kreativ.
Diese Behandlung von Listen ist in Kombination mit dem Mustervergleich SEHR leistungsfähig. Angenommen, ich möchte eine Liste von Zahlen zusammenfassen:
let rec Sum numbers =
match numbers with
| [] -> 0
| head::tail -> head + Sum tail
Dies besagt im Wesentlichen "Wenn wir mit einer leeren Liste aufgerufen wurden, geben Sie 0 zurück" (damit wir die Rekursion unterbrechen können), andernfalls geben Sie den Wert von head + den Wert von Sum zurück, der mit den verbleibenden Elementen aufgerufen wurde (daher unsere Rekursion).
Zum Beispiel könnte ich eine Liste von URLs haben , ich denke, alle URLs, auf die jede URL verweist, aufteilen und dann die Gesamtzahl der Links zu / von allen URLs reduzieren, um "Werte" für eine Seite zu generieren (ein Ansatz, den Google verfolgt nimmt mit PageRank und das finden Sie definiert im Original MapReduce Papier). Sie können dies auch tun, um Wortzahlen in einem Dokument zu generieren. Und viele, viele, viele andere Dinge auch.
Sie können dieses Funktionsmuster auf jede Art von MapReduce- Code erweitern, in dem Sie eine Liste von etwas erstellen, transformieren und etwas anderes zurückgeben können (ob eine andere Liste oder ein Zip-Befehl in der Liste).
Ich habe einmal in meiner Karriere Rekursion verwendet, und als sich das Framework änderte, wurde ich es los. 80% von dem, was wir tun, ist CRUD.
Charles Graham
1
"XML" überhaupt zu erwähnen ist ziemlich seltsam. Es ist keine natürliche Sache, nichts, mit dem sich ein gewöhnlicher Mensch, den Sie unterrichten werden, im Alltag auseinandersetzen muss. Aber die Idee ist natürlich durchaus sinnvoll.
imz - Ivan Zakharyaschev
3
Rückkopplungsschleifen in einer hierarchischen Organisation.
Der Top-Chef fordert die Top-Führungskräfte auf, Feedback von allen Mitarbeitern des Unternehmens einzuholen.
Jede Führungskraft sammelt ihre direkten Berichte und fordert sie auf, Feedback von ihren direkten Berichten einzuholen.
Und auf der ganzen Linie.
Personen ohne direkte Berichte - die Blattknoten im Baum - geben ihr Feedback.
Das Feedback wird wieder in den Baum aufgenommen, wobei jeder Manager sein eigenes Feedback hinzufügt.
Schließlich schafft es das gesamte Feedback zurück zum Top-Boss.
Dies ist die natürliche Lösung, da die rekursive Methode das Filtern auf jeder Ebene ermöglicht - das Zusammenstellen von Duplikaten und das Entfernen von anstößigem Feedback. Der Top-Chef könnte eine globale E-Mail senden und jeden Mitarbeiter direkt Feedback an ihn / sie zurückgeben lassen. Es gibt jedoch die Probleme "Sie können nicht mit der Wahrheit umgehen" und "Sie werden gefeuert", sodass die Rekursion hier am besten funktioniert.
Angenommen, Sie erstellen ein CMS für eine Website, auf der sich Ihre Seiten in einer Baumstruktur befinden. Der Stamm ist beispielsweise die Startseite.
Angenommen, Ihr {Benutzer | Kunde | Kunde | Chef} fordert Sie auf, auf jeder Seite einen Breadcrumb-Pfad zu platzieren, um anzuzeigen, wo Sie sich im Baum befinden.
Für eine bestimmte Seite n möchten Sie möglicherweise rekursiv zum übergeordneten Element von n und seinem übergeordneten Element usw. gehen, um eine Liste von Knoten bis zum Stammverzeichnis des Seitenbaums zu erstellen.
Natürlich treffen Sie in diesem Beispiel die Datenbank mehrmals pro Seite. Daher möchten Sie möglicherweise ein SQL-Aliasing verwenden, bei dem Sie die Seitentabelle als a und die Seitentabelle erneut als b nachschlagen und a.id mit beitreten b.parent, damit die Datenbank die rekursiven Joins ausführt. Es ist schon eine Weile her, daher ist meine Syntax wahrscheinlich nicht hilfreich.
Andererseits möchten Sie dies möglicherweise nur einmal berechnen und mit dem Seitendatensatz speichern und nur aktualisieren, wenn Sie die Seite verschieben. Das wäre wahrscheinlich effizienter.
Sie haben einen Organisationsbaum, der N Ebenen tief ist. Einige der Knoten werden überprüft, und Sie möchten nur die Knoten erweitern, die überprüft wurden.
Dies ist etwas, das ich tatsächlich codiert habe. Es ist schön und einfach mit Rekursion.
In meinem Job haben wir ein System mit einer generischen Datenstruktur, die als Baum beschrieben werden kann. Das bedeutet, dass die Rekursion eine sehr effektive Technik ist, um mit den Daten zu arbeiten.
Das Lösen ohne Rekursion würde viel unnötigen Code erfordern. Das Problem bei der Rekursion ist, dass es nicht einfach ist zu verfolgen, was passiert. Sie müssen sich wirklich konzentrieren, wenn Sie dem Ablauf der Ausführung folgen. Aber wenn es funktioniert, ist der Code elegant und effektiv.
"XML" ist für die Idee dieser Antwort nicht wesentlich (und das spezifische Erwähnen von XML kann die Leute, die Sie unterrichten, ekelhaft / langweilig machen). Nur eine typische Sprache (eine Computersprache oder eine natürliche Sprache) würde als Beispiel für ein rekursives Parsing-Problem dienen.
imz - Ivan Zakharyaschev
Das Poster fragte nach "realen Problemen, bei denen ein rekursiver Ansatz die natürliche Lösung ist". Das Parsen einer XML-Datei ist sicherlich ein reales Problem und eignet sich natürlich für eine Rekursion. Die Tatsache, dass Sie eine seltsame Abneigung gegen XML zu haben scheinen, ändert nichts an der Tatsache, dass es sehr weit verbreitet ist.
Dima
2
Analysieren eines Steuerelementbaums in Windows Forms oder WebForms (.NET Windows Forms / ASP.NET ).
Die Verbindung ist unterbrochen. Können Sie den Titel des Buches hinzufügen?
Peter Mortensen
@ PeterMortensen, das Buch ist Beautiful Code von Greg Wilson und Andy Oram. Ich habe den Link aktualisiert, obwohl O'Reilly anscheinend nicht mehr hineinschauen darf. Aber Sie können einen Blick auf Amazon werfen.
Fabio Ceconello
1
Telefon- und Kabelunternehmen verwalten ein Modell ihrer Verkabelungstopologie, bei dem es sich tatsächlich um ein großes Netzwerk oder eine Grafik handelt. Rekursion ist eine Möglichkeit, dieses Modell zu durchlaufen, wenn Sie alle übergeordneten oder alle untergeordneten Elemente finden möchten.
Da die Rekursion aus Verarbeitungs- und Speichersicht teuer ist, wird dieser Schritt normalerweise nur ausgeführt, wenn die Topologie geändert und das Ergebnis in einem modifizierten vorbestellten Listenformat gespeichert wird.
Das Gleiche gilt für den Kommentar zu Compilern. Die abstrakten Syntaxbaumknoten eignen sich natürlich für eine Rekursion. Alle rekursiven Datenstrukturen (verknüpfte Listen, Bäume, Diagramme usw.) können auch einfacher mit Rekursion behandelt werden. Ich denke, dass die meisten von uns aufgrund der Art der Probleme in der realen Welt nicht viel Rekursion verwenden können, wenn sie nicht zur Schule gehen, aber es ist gut, sich dessen als Option bewusst zu sein.
Antworten:
Es gibt hier viele mathematische Beispiele, aber Sie wollten ein Beispiel aus der realen Welt. Mit ein wenig Nachdenken ist dies möglicherweise das Beste, was ich anbieten kann:
Sie finden eine Person, die sich eine bestimmte ansteckende Infektion zugezogen hat, die nicht tödlich ist und sich schnell selbst behebt (Typ A), mit Ausnahme von einer von fünf Personen (wir nennen diese Typ B), die dauerhaft damit infiziert sind und keine aufweisen Symptome und wirkt lediglich als Spreader.
Dies erzeugt ziemlich nervige Verwüstungswellen, wenn Typ B jemals eine Vielzahl von Typ A infiziert.
Ihre Aufgabe ist es, alle Typ B aufzuspüren und zu immunisieren, um das Rückgrat der Krankheit zu stoppen. Leider können Sie nicht allen ein landesweites Heilmittel verabreichen, da die Menschen, die Typ As sind, auch tödlich allergisch gegen das Heilmittel sind, das für Typ B wirkt.
Die Art und Weise, wie Sie dies tun würden, wäre eine soziale Entdeckung, wenn eine infizierte Person (Typ A) in der letzten Woche alle ihre Kontakte auswählt und jeden Kontakt auf einem Haufen markiert. Wenn Sie testen, ob eine Person infiziert ist, fügen Sie sie der Warteschlange "Follow-up" hinzu. Wenn eine Person vom Typ B ist, fügen Sie sie dem "Follow-up" am Kopf hinzu (weil Sie dies schnell stoppen möchten).
Wählen Sie nach der Verarbeitung einer bestimmten Person die Person an der Vorderseite der Warteschlange aus und wenden Sie bei Bedarf eine Impfung an. Holen Sie sich alle zuvor nicht besuchten Kontakte und testen Sie, ob sie infiziert sind.
Wiederholen Sie diesen Vorgang, bis die Warteschlange infizierter Personen 0 wird, und warten Sie dann auf einen weiteren Ausbruch.
(Ok, dies ist ein bisschen iterativ, aber es ist eine iterative Methode zur Lösung eines rekursiven Problems. In diesem Fall wird die erste Durchquerung einer Bevölkerungsbasis versucht, wahrscheinliche Wege zu Problemen zu finden. Außerdem sind iterative Lösungen häufig schneller und effektiver und ich entferne zwanghaft die Rekursion überall so sehr, dass sie instinktiv wird. .... verdammt!)
quelle
Ein reales Beispiel für Rekursion
quelle
Wie wäre es mit einer Verzeichnisstruktur im Dateisystem? Rekursives Suchen von Dateien, Löschen von Dateien, Erstellen von Verzeichnissen usw.
Hier ist eine Java-Implementierung, die den Inhalt eines Verzeichnisses und seiner Unterverzeichnisse rekursiv druckt.
quelle
Quicksort , Zusammenführungssortierung und die meisten anderen N-log N-Sortierungen.
quelle
Matt Dillards Beispiel ist gut. Im Allgemeinen kann jedes Gehen eines Baumes im Allgemeinen sehr einfach durch Rekursion gehandhabt werden. Zum Beispiel das Kompilieren von Analysebäumen, das Gehen über XML oder HTML usw.
quelle
Rekursion wird häufig in Implementierungen des Backtracking-Algorithmus verwendet . Wie wäre es mit einem Sudoku-Löser für eine "reale" Anwendung ?
quelle
Rekursion ist immer dann angebracht, wenn ein Problem gelöst werden kann, indem es in Unterprobleme unterteilt wird, die denselben Algorithmus zur Lösung verwenden können. Algorithmen für Bäume und sortierte Listen passen natürlich zusammen. Viele Probleme in der Computergeometrie (und in 3D-Spielen) können rekursiv mithilfe von BSP-Bäumen ( Binary Space Partitioning ), fetten Unterteilungen oder anderen Methoden zur Aufteilung der Welt in Unterteile gelöst werden .
Rekursion ist auch angebracht, wenn Sie versuchen, die Richtigkeit eines Algorithmus zu gewährleisten. Bei einer Funktion, die unveränderliche Eingaben akzeptiert und ein Ergebnis zurückgibt, das eine Kombination aus rekursiven und nicht rekursiven Aufrufen der Eingaben darstellt, ist es normalerweise einfach, mithilfe mathematischer Induktion zu beweisen, dass die Funktion korrekt ist (oder nicht). Es ist oft schwierig, dies mit einer iterativen Funktion oder mit Eingaben zu tun, die mutieren können. Dies kann nützlich sein, wenn Sie sich mit Finanzberechnungen und anderen Anwendungen befassen, bei denen die Korrektheit sehr wichtig ist.
quelle
Sicherlich verwenden viele Compiler die Rekursion stark. Computersprachen sind von Natur aus rekursiv (dh Sie können if-Anweisungen in andere if-Anweisungen usw. einbetten).
quelle
Deaktivieren / Festlegen der schreibgeschützten Steuerung für alle untergeordneten Steuerelemente in einem Containersteuerelement. Ich musste dies tun, weil einige der Kinderkontrollen selbst Container waren.
quelle
Berühmter Eval / Apply-Zyklus von SICP
(Quelle: mit.edu )
Hier ist die Definition von eval:
Hier ist die Definition von anwenden:
Hier ist die Definition der Eval-Sequenz:
eval
->apply
->eval-sequence
->eval
quelle
Rekursion wird in Dingen wie BSP-Bäumen zur Kollisionserkennung in der Spieleentwicklung (und anderen ähnlichen Bereichen) verwendet.
quelle
Menschen sortieren häufig Stapel von Dokumenten mit einer rekursiven Methode. Stellen Sie sich zum Beispiel vor, Sie sortieren 100 Dokumente mit Namen. Legen Sie die Dokumente zuerst nach dem ersten Buchstaben in Stapel und sortieren Sie dann jeden Stapel.
Das Nachschlagen von Wörtern im Wörterbuch wird häufig durch eine rekursive Binärsuchtechnik durchgeführt.
In Organisationen erteilen Chefs häufig Abteilungsleiter, die wiederum den Managern Befehle erteilen, und so weiter.
quelle
Anforderungen an die reale Welt, die ich kürzlich erhalten habe:
Anforderung A: Implementieren Sie diese Funktion, nachdem Sie Anforderung A gründlich verstanden haben.
quelle
Parser und Compiler können in einer rekursiven Abstiegsmethode geschrieben werden. Nicht der beste Weg, dies zu tun, da Tools wie lex / yacc schnellere und effizientere Parser generieren, aber konzeptionell einfach und leicht zu implementieren sind, sodass sie weiterhin üblich sind.
quelle
Die Rekursion wird auf Probleme (Situationen) angewendet, in denen Sie sie in kleinere Teile aufteilen (reduzieren) können und jedes Teil dem ursprünglichen Problem ähnelt.
Gute Beispiele dafür, wo Dinge, die kleinere Teile enthalten, die sich selbst ähnlich sind, sind:
Rekursion ist eine Technik, um das Problem in immer kleinere Teile zu zerlegen, bis eines dieser Teile klein genug wird, um ein Kinderspiel zu sein. Nachdem Sie sie aufgelöst haben, müssen Sie die Ergebnisse natürlich wieder in der richtigen Reihenfolge "zusammennähen", um eine vollständige Lösung Ihres ursprünglichen Problems zu erhalten.
Einige rekursive Sortieralgorithmen, Tree-Walking-Algorithmen, Map / Reduce-Algorithmen, Divide-and-Conquer sind Beispiele für diese Technik.
In der Computerprogrammierung verfügen die meisten stapelbasierten Call-Return-Sprachen bereits über die für die Rekursion integrierten Funktionen:
quelle
Ich habe ein System, das an einigen Stellen eine reine Schwanzrekursion verwendet , um eine Zustandsmaschine zu simulieren.
quelle
Einige gute Beispiele für Rekursionen finden sich in funktionalen Programmiersprachen . In funktionalen Programmiersprachen ( Erlang , Haskell , ML / OCaml / F # usw.) ist es sehr häufig, dass bei der Listenverarbeitung eine Rekursion verwendet wird.
Beim Umgang mit Listen in typischen imperativen OOP-Sprachen werden Listen häufig als verknüpfte Listen implementiert ([item1 -> item2 -> item3 -> item4]). In einigen funktionalen Programmiersprachen werden Listen selbst jedoch rekursiv implementiert, wobei der "Kopf" der Liste auf das erste Element in der Liste und das "Ende" auf eine Liste zeigt, die den Rest der Elemente enthält ( [item1 -> [item2 -> [item3 -> [item4 -> []]]]). Es ist meiner Meinung nach ziemlich kreativ.
Diese Behandlung von Listen ist in Kombination mit dem Mustervergleich SEHR leistungsfähig. Angenommen, ich möchte eine Liste von Zahlen zusammenfassen:
Dies besagt im Wesentlichen "Wenn wir mit einer leeren Liste aufgerufen wurden, geben Sie 0 zurück" (damit wir die Rekursion unterbrechen können), andernfalls geben Sie den Wert von head + den Wert von Sum zurück, der mit den verbleibenden Elementen aufgerufen wurde (daher unsere Rekursion).
Zum Beispiel könnte ich eine Liste von URLs haben , ich denke, alle URLs, auf die jede URL verweist, aufteilen und dann die Gesamtzahl der Links zu / von allen URLs reduzieren, um "Werte" für eine Seite zu generieren (ein Ansatz, den Google verfolgt nimmt mit PageRank und das finden Sie definiert im Original MapReduce Papier). Sie können dies auch tun, um Wortzahlen in einem Dokument zu generieren. Und viele, viele, viele andere Dinge auch.
Sie können dieses Funktionsmuster auf jede Art von MapReduce- Code erweitern, in dem Sie eine Liste von etwas erstellen, transformieren und etwas anderes zurückgeben können (ob eine andere Liste oder ein Zip-Befehl in der Liste).
quelle
XML oder das Durchlaufen von Bäumen. Obwohl ich, um ehrlich zu sein, in meinem Job so gut wie nie Rekursion verwende.
quelle
Rückkopplungsschleifen in einer hierarchischen Organisation.
Der Top-Chef fordert die Top-Führungskräfte auf, Feedback von allen Mitarbeitern des Unternehmens einzuholen.
Jede Führungskraft sammelt ihre direkten Berichte und fordert sie auf, Feedback von ihren direkten Berichten einzuholen.
Und auf der ganzen Linie.
Personen ohne direkte Berichte - die Blattknoten im Baum - geben ihr Feedback.
Das Feedback wird wieder in den Baum aufgenommen, wobei jeder Manager sein eigenes Feedback hinzufügt.
Schließlich schafft es das gesamte Feedback zurück zum Top-Boss.
Dies ist die natürliche Lösung, da die rekursive Methode das Filtern auf jeder Ebene ermöglicht - das Zusammenstellen von Duplikaten und das Entfernen von anstößigem Feedback. Der Top-Chef könnte eine globale E-Mail senden und jeden Mitarbeiter direkt Feedback an ihn / sie zurückgeben lassen. Es gibt jedoch die Probleme "Sie können nicht mit der Wahrheit umgehen" und "Sie werden gefeuert", sodass die Rekursion hier am besten funktioniert.
quelle
Angenommen, Sie erstellen ein CMS für eine Website, auf der sich Ihre Seiten in einer Baumstruktur befinden. Der Stamm ist beispielsweise die Startseite.
Angenommen, Ihr {Benutzer | Kunde | Kunde | Chef} fordert Sie auf, auf jeder Seite einen Breadcrumb-Pfad zu platzieren, um anzuzeigen, wo Sie sich im Baum befinden.
Für eine bestimmte Seite n möchten Sie möglicherweise rekursiv zum übergeordneten Element von n und seinem übergeordneten Element usw. gehen, um eine Liste von Knoten bis zum Stammverzeichnis des Seitenbaums zu erstellen.
Natürlich treffen Sie in diesem Beispiel die Datenbank mehrmals pro Seite. Daher möchten Sie möglicherweise ein SQL-Aliasing verwenden, bei dem Sie die Seitentabelle als a und die Seitentabelle erneut als b nachschlagen und a.id mit beitreten b.parent, damit die Datenbank die rekursiven Joins ausführt. Es ist schon eine Weile her, daher ist meine Syntax wahrscheinlich nicht hilfreich.
Andererseits möchten Sie dies möglicherweise nur einmal berechnen und mit dem Seitendatensatz speichern und nur aktualisieren, wenn Sie die Seite verschieben. Das wäre wahrscheinlich effizienter.
Wie auch immer, das sind meine $ .02
quelle
Sie haben einen Organisationsbaum, der N Ebenen tief ist. Einige der Knoten werden überprüft, und Sie möchten nur die Knoten erweitern, die überprüft wurden.
Dies ist etwas, das ich tatsächlich codiert habe. Es ist schön und einfach mit Rekursion.
quelle
In meinem Job haben wir ein System mit einer generischen Datenstruktur, die als Baum beschrieben werden kann. Das bedeutet, dass die Rekursion eine sehr effektive Technik ist, um mit den Daten zu arbeiten.
Das Lösen ohne Rekursion würde viel unnötigen Code erfordern. Das Problem bei der Rekursion ist, dass es nicht einfach ist zu verfolgen, was passiert. Sie müssen sich wirklich konzentrieren, wenn Sie dem Ablauf der Ausführung folgen. Aber wenn es funktioniert, ist der Code elegant und effektiv.
quelle
Berechnungen für Finanzen / Physik, wie zusammengesetzte Durchschnittswerte.
quelle
quelle
Analysieren eines Steuerelementbaums in Windows Forms oder WebForms (.NET Windows Forms / ASP.NET ).
quelle
Das beste Beispiel, das ich kenne, ist Quicksort. Mit Rekursion ist es viel einfacher. Schauen Sie sich an:
shop.oreilly.com/product/9780596510046.do
www.amazon.com/Beautiful-Code-Leading-Programmers-Practice/dp/0596510047
(Klicken Sie auf den ersten Untertitel unter Kapitel 3: "Der schönste Code, den ich je geschrieben habe").
quelle
Telefon- und Kabelunternehmen verwalten ein Modell ihrer Verkabelungstopologie, bei dem es sich tatsächlich um ein großes Netzwerk oder eine Grafik handelt. Rekursion ist eine Möglichkeit, dieses Modell zu durchlaufen, wenn Sie alle übergeordneten oder alle untergeordneten Elemente finden möchten.
Da die Rekursion aus Verarbeitungs- und Speichersicht teuer ist, wird dieser Schritt normalerweise nur ausgeführt, wenn die Topologie geändert und das Ergebnis in einem modifizierten vorbestellten Listenformat gespeichert wird.
quelle
Induktives Denken, der Prozess der Konzeptbildung, ist rekursiver Natur. Ihr Gehirn tut es die ganze Zeit in der realen Welt.
quelle
Das Gleiche gilt für den Kommentar zu Compilern. Die abstrakten Syntaxbaumknoten eignen sich natürlich für eine Rekursion. Alle rekursiven Datenstrukturen (verknüpfte Listen, Bäume, Diagramme usw.) können auch einfacher mit Rekursion behandelt werden. Ich denke, dass die meisten von uns aufgrund der Art der Probleme in der realen Welt nicht viel Rekursion verwenden können, wenn sie nicht zur Schule gehen, aber es ist gut, sich dessen als Option bewusst zu sein.
quelle
Die Multiplikation natürlicher Zahlen ist ein reales Beispiel für Rekursion:
quelle