Tail-rekursive Merge-Sortierung in OCaml

8

Ich versuche, eine tail-rekursive Listensortierfunktion in OCaml zu implementieren, und ich habe den folgenden Code entwickelt:

%Vor%

Aber es scheint, dass es nicht tatsächlich tail-rekursiv ist, da ich einen "Stapelüberlauf während der Auswertung (Schleifenrekursion?)" -Fehler erfahre.

Könnten Sie mir bitte helfen, den nicht tailrekursiven Aufruf in diesem Code zu erkennen? Ich habe ziemlich viel gesucht, ohne es zu finden. Könnte es die gebundene Bindung in der Funktion sort sein?

    
Clément 27.03.2010, 14:17
quelle

2 Antworten

7

Der Ausdruck

%Vor%

ist nicht tail-rekursiv; Es ruft sowohl (nach links sortieren) als auch (nach rechts) rekursiv auf, solange noch Arbeit im Aufruf ist (Zusammenführen).

Ich denke, Sie können es mit einem zusätzlichen Fortsetzungsparameter beheben:

%Vor%     
Brian 27.03.2010, 14:33
quelle
9

Merge sort ist inhärent nicht tail-rekursiv. Eine Sortierung erfordert zwei rekursive Aufrufe und bei jeder Ausführung einer Funktion höchstens eins dynamischer Aufruf kann in Endposition sein. ( split wird auch von der Nicht-Tail-Position aufgerufen, aber da es einen konstanten Stapelspeicherplatz verwenden sollte, der OK sein sollte).

Stellen Sie sicher, dass Sie eine aktuelle Version von OCaml verwenden. In Versionen 3.08 und älter könnte List.rev den Stack durchbrechen. Dieses Problem wurde in Version 3.10 behoben. Mit Version 3.10.2 kann ich eine Liste von zehn Millionen Elementen mit Ihrem Code sortieren. Es dauert ein paar Minuten, aber ich blase den Stapel nicht. Ich hoffe also, dass dein Problem einfach darin besteht, dass du eine alte Version von OCaml hast.

Wenn nicht, wäre ein guter nächster Schritt, die Umgebungsvariable

zu setzen %Vor%

gibt eine Stapelspur, wenn Sie den Stapel blasen.

Ich möchte auch die Länge der Arrays wissen, die Sie sortieren; Obwohl Merge-Sort nicht tail-rekursiv sein kann, sollte seine Nicht-Tail-Eigenschaft Sie logarithmischen Stack-Speicherplatz kosten.

Wenn Sie mehr als 10 Millionen Elemente sortieren müssen, sollten Sie sich vielleicht einen anderen Algorithmus anschauen? Oder, wenn Sie möchten, könnten Sie CPS-Mergesort von Hand konvertieren, was eine tail-rekursive Version auf Kosten der Zuweisung von Contiuations auf dem Heap ergeben wird. Aber ich schätze, dass es nicht notwendig sein wird.

    
Norman Ramsey 27.03.2010 22:12
quelle

Tags und Links