staticvoiddown2(int n ){if( n <=0)// Rekursionsendereturn;down2( n – 1);System.out.print( n +", ");}
Bei down2(10) wird "1, 2, 3, 4, 5, 6, 7, 8, 9, 10," ausgegeben und nicht - wie meine Logik die Lösung sehen würde - nichts. Sagen wir down2(10), also wird down2(10-1) ausgerufen, also ist n = 9, also down2(9) praktisch. Und das so lange, bis n = 0 ist (wegen Rekursion, Zeile 6).
In der Methode steht aber doch direkt ganz am Anfang, dass falls n <= 0 ist, die Methode beendet werden soll, also warum wird da überhaupt ETWAS ausgegeben (und dann auch noch von 1 aufsteigend :autsch Wo ist hier bitteschön n + 1, weswegen n = 1 wäre (denn n ist ja nach der ganzen Subtraktion wegen Rekursion erst einmal = 0!)?
Du musst dir einfach vorstellen, dass die Methode 10mal (bzw. 11mal) aufgerufen wird und danach in umgekehrter Reihenfolge an der Stelle fortgesetzt wird (und die Ausgabe erfolgt), an der der Methodenaufruf steht
1. selbst wenn down2(1) wäre, so müsste doch wieder in Zeile 6 down2(n - 1) aufgerufen werden, also wäre wieder n = 0.
2. Wieso down2(1), wenn ich down2() doch mit dem Argument 10 aufrufe? Na klar, erst wird alles bis 0 subtrahiert, aber wo zum Teufel wird n mit 1 addiert? Das sehe ich nirgendswo ...
Wenn die Methode zu ihrem Aufrufer zurückkehrt wird logischerweise ab dem Funktionsaufruf weitergearbeitet, also ab Zeile 8.
down2(0) kehrt zu down(1) zurück und arbeitet ab Zeile 8 weiter, denn es wurde selber in Zeile 7 aufgerufen.
Nein, an der Zeile 6 bist du ja zu dem Zeitpunkt schon vorbei.
Du solltest dich mal mit den Grundlagen eines Stacks befassen. Die Methodenaufrufe werden da in der richtigen Reihenfolge mit dem entsprechenden Parameter draufgelegt und dann zum Schluss wieder in umgekehrter Reihenfolge abgearbeitet. Am Ende "liegt" down(0) ganz zuoberst, beendet mit return und wirft den Aufruf vom Stack.
Anschließend nimmt er den Aufruf down(1) vom Stapel und gibt die Zahl 1 aus, beendet den Methodenaufruf regulär und nimmt sich den nächsten Aufruf vor.
Wenn die Methode zu ihrem Aufrufer zurückkehrt wird logischerweise ab dem Funktionsaufruf weitergearbeitet, also ab Zeile 8.
down2(0) kehrt zu down(1) zurück und arbeitet ab Zeile 8 weiter, denn es wurde selber in Zeile 7 aufgerufen.
staticvoiddown2(int n ){if( n <=0)// Rekursionsendereturn;staticvoiddown2(int n ){if( n <=0)// Rekursionsendereturn;staticvoiddown2(int n ){if( n <=0)// Rekursionsendereturn;staticvoiddown2(int n ){if( n <=0)// Rekursionsendereturn;staticvoiddown2(int n ){if( n <=0)// Rekursionsendereturn;down2( n – 1);System.out.print( n +", ");}System.out.print( n +", ");}System.out.print( n +", ");}System.out.print( n +", ");}System.out.print( n +", ");}
Also eine Erklärung zu Stacks aus dem Internet besagt:
"Am Beispiel haben wir gesehen, dass der Aufruf von down2(10) zum Aufruf von down2(9) führt. Und down2(10) kann erst dann beendet werden, wenn down2(9) komplett abgearbeitet wurde. down2(10) ist sozusagen so lange »offen«, bis der Schwanz von untergeordneten Aufrufen beendet ist" (Quelle: Galileo Computing :: Java ist auch eine Insel - 2 Imperative Sprachkonzepte)
Das heißt mit anderen Worten: In dem Moment, wo in Zeile 6
Java:
down2(n -1);
aufgerufen wird und n den Wert 0 annimmt, sind die n-Werte 1 bis 10 noch offen, und dann wird jeweils mit den n-Werten nacheinander print() ausgeführt, da die Methode alles bis Zeile 10 (also print()) überspringt, SOFERN n <= 0 ist.
Doch wieso überspringt die Methode das alles? Müsste return; nicht auch fürt print() gelten? Denn return; beendet doch eine Methode, soweit ich mich in das Thema eingelesen habe, und print() ist doch in der Methode drin.
Da wird nichts übersprungen. Alles bis Zeile 10 wurde bereits auf dem "Hinweg" (VOR dem Methodenaufruf in Zeile 6) abgearbeitet. Auf dem "Rückweg" (NACH dem Methodenaufruf) wird dann nur noch der Rest ausgeführt (das Print).
Edit: Rekursion ist eben nicht für jeden sofort verständlich, aber wenn man den Dreh mal raus hat, ists kein Hexenwerk mehr.
Also ich weiß bisher, dass die Methode solange ausgeführt wird, bis n = 0 ist. Also:
Java:
publicclass hae {staticvoiddown2(int n)// bis hier n = 0 ist!{if( n <=0)return;down2(n -1);System.out.print(n +", ");}}
Aber in Zeile 4 steht doch, falls n <= 0 ist, wird die Methode nicht mehr ausgeführt. Also müsste Schluss sein. Denn oben bei static void down2(int n) ist n ja nicht mehr 1, sondern 0, wegen Zeile 6 "down2(n-1)", und dort ist n nach einigen Aufrufen schon bei 1 ..
Wenn ein return in einer Methode auftaucht, so kehrt sie zu ihrem Aufrufer zurück. Da das hier aber rekursiv ist und die Methode sich selbst aufruft, kehrt sie auch zu sich selbst zurück. Somit kehrt hier ab n=0 die methode 10 mal nacheinander jeweils zu down2(n+1) zurück.
Wen du ne methode schreibst und sie aufrufst und diese dann ein return hat, dann wird sie ja auch nicht nochmal aufgerufen sondern es wird in der Zeile nach dem Aufruf weitergearbeitet. Ansonsten wäre das ja eine Endlosschleife.
hmmmmm, aber n ist doch überall = 0 zum Schluss, also dürfte print() gar nicht ausgeführt werden X_X denn selbst bei down2(n+1) wäre "n <= 0" falsch, sodass wieder down2(n-1) ausgeführt werden müsste...
n hat in jedem Methodenaufruf immer noch den Wert, den er beim Aufruf mitbekommen hat. Also es gibt für jede Zahl 1 bis 10 eine Methode auf dem Stack, für die n diesen Wert hat.
publicclass hae {staticvoiddown2(int n)// 1. Durchgang: n = 10{if( n <=0)return;down2(n -1);System.out.print(n +", ");}staticvoiddown2(int n)// 2. Durchgang: n = 9{if( n <=0)return;down2(n -1);System.out.print(n +", ");}staticvoiddown2(int n)// 3. Durchgang: n = 8{if( n <=0)return;down2(n -1);System.out.print(n +", ");}staticvoiddown2(int n)// 4. Durchgang: n = 7{if( n <=0)return;down2(n -1);System.out.print(n +", ");}staticvoiddown2(int n)// 5. Durchgang: n = 6{if( n <=0)return;down2(n -1);System.out.print(n +", ");}staticvoiddown2(int n)// 7. Durchgang: n = 5{if( n <=0)return;down2(n -1);System.out.print(n +", ");}staticvoiddown2(int n)// 8. Durchgang: n = 4{if( n <=0)return;down2(n -1);System.out.print(n +", ");}staticvoiddown2(int n)// 9. Durchgang: n = 3{if( n <=0)return;down2(n -1);System.out.print(n +", ");}staticvoiddown2(int n)// 10. Durchgang: n = 2{if( n <=0)return;down2(n -1);System.out.print(n +", ");}staticvoiddown2(int n)// 11. Durchgang: n = 1{if( n <=0)return;down2(n -1);System.out.print(n +", ");}staticvoiddown2(int n)// 12. Durchgang: Hier ist n = 0, also wird die Methode beendet und dann ab dem 11. Durchgang (1 Schritt zurück) geht es ab print(); weiter?{if( n <=0)return;down2(n -1);System.out.print(n +", ");}}
Das hier hilft vielleicht, oder bewirkt genau das Gegenteil, weil SO viel ausgegeben wird, dass man gar nicht mehr durchblickt:
Java:
classDownTest{publicstaticvoidmain(String args[]){down(10);}staticvoiddown(int n ){print(10-n,"Entering with n="+n);if( n <=0)// Rekursionsende{print(10-n,"Nothing to do in down("+n+")");return;}print(10-n,"Recursive call from down("+n+") to down("+(n-1)+")");down( n -1);print(10-n,"Returned from recursive call down("+(n-1)+") back to to down("+n+")");print(10-n,"Printing from down("+n+")");System.out.println( n +", ");print(10-n,"Returning from down("+n+")");}privatestaticvoidprint(int n,String text){System.out.printf("%-"+(n*2+1)+"s"+text+"\n","");}}
Also ist eigentlich dieses down2(n-1) immer eine neue Methode und nicht die eigentliche Methode down2(int n), richtig? Das erklärt dann eigentlich alles...
Also ist eigentlich dieses down2(n-1) immer eine neue Methode und nicht die eigentliche Methode down2(int n), richtig? Das erklärt dann eigentlich alles...
Doch, es ist genau dieselbe Methode. Nur eben eine Methode, die sich selbst immer wieder mit einem anderen Wert aufruft. Alle vorherigen Aufrufe bleiben aber bis dahin bestehen. Rekursion eben.
Doch, es ist genau dieselbe Methode. Nur eben eine Methode, die sich selbst immer wieder mit einem anderen Wert aufruft. Alle vorherigen Aufrufe bleiben aber bis dahin bestehen. Rekursion eben.
Normalerweise besteht eine rekursive Methode immer aus einer Abbruchbedingung, einer Parameteränderung und einem rekursiven Aufruf.
Und mach dir das mit dem Stack nochmal klar. Jede aufgerufene Methode wird "oben" auf den Stack gelegt. Wenn eine Methode beendet ist ( } erreicht oder return; (oder Exception) ), dann wird sie vom Stack genommen und die oberste auf dem Stack wird weiter ausgeführt
Wenn man die print-Methode leicht erweitert, sieht man sogar die "Lebenslinie" der einzelnen Methoden:
Java:
privatestaticvoidprint(int n,String text){for(int i=0; i++< n;)System.out.printf("%-"+(i*2+1)+"s|","");System.out.printf("%-"+( n *2+1)+"s"+ text +"\n","");}
Und statt
Java:
System.out.println( n +", ");
würde ich auch dringend
Java:
print(10- n,String.valueOf(n));
empfehlen. Ist eigentlich ein ziemlich interessanter Ansatz, das zu erklären, könnte man sicher oft wiederverwenden.