Es geht praktisch in quicksort rein (also 1.Zeile).
da werden die Daten jetzt also weitergereicht in _quicksort?
Genau. Das dient vermutlich einerseits um es dem Anwender bequemer zu machen die Sortiermethode zu benutzen und andererseits dient es dem
information hiding. Der Anwender braucht (und soll) gar nicht wissen das in dem Quicksort-Algorithmus irgendwelche Arraygrenzen verwendet werden.
also: _quicksort(a,0,a.length-1)
d.h. also a,0,3 (weil das Array 4 Elemente hat???)
0 ist die linke Grenze also der Anfang des Arrays und 3 das Ende.
Genau. Ein Array von nur 4 Elementen ist allerdings etwas zu klein um wirklich zu erkennen was Quicksort macht. Verwende doch stattdessen mal ein Array mit 10 Elementen, z.B. [c]{3, 0, 1, 8, 7, 2, 5, 4, 9, 6}[/c]
Der Grundgedanke bei Quicksort ist nun: Wir wählen ein beliebiges Element des Arrays aus (im folgenden
Referenzelement genannt, wir wählen jetzt mal das erste Element: Die 3) und sorgen dafür das dieses Element an seine endgültige Position im Array wandert. Wir wissen zwar noch nicht wo diese Position ist, aber wir können sie folgendermaßen beschreiben: Das Referenzelement befindet sich genau dann an seiner endgültigen Position wenn alle Werte "links" vom Referenzelement kleiner/gleich sind als das Referenzelement. Ebenso müssen alle Werte "rechts" vom Referenzelement größer/gleich dem Referenzelement sein.
Wenn wir unser Array also derart modifizieren könnten das es beispielsweise so aussieht: [c]{2, 0, 1, _3_, 7, 8, 5, 4, 9, 6}[/c] Dann wissen wir das sich unser Referenzelement (3) bereits an seiner
endgültigen Position befindet, so daß wir es nie wieder betrachten müssen. Alle Werte links von der drei sind kleiner/gleich 3, alle Werte rechts davon sind größer/gleich 3. Und dieses Wissen nutzen wir gleich aus.
Aber erstmal stellt sich ja die Frage wie wir das Array überhaupt so modifizieren, das die beiden oben genannten Bedingungen erfüllt sind. Na, das ist eigentlich nicht schwer. Wir vergleichen das Referenzelement halt der Reihe nach mit allen anderen Werten des Arrays. Sollten wir dabei feststellen, das unsere Bedingungen mal nicht erfüllt sind (also ein Element < 3 rechts vom Referenzelement steht, oder ein Element > 3 links vom Referenzelement) dann vertauschen wir das Referenzelement und das falsch positionierte Element einfach. Nach dem Vertauschen fahren wir dann wie gewohnt mit dem Vergleichen der restlichen Elemente fort.
Diesen gesamten Vorgang, also ein Referenzelement an seine endgültige Position zu schieben, erledigt bei dir die Methode
partition. Dafür bekommt sie das zu sortierende Array sowie die linke und rechte Grenze des zu verarbeitenden Bereichs innerhalb des Arrays übergeben (zu den Grenzen gleich mehr; beim allerersten Aufruf bearbeitet die Methode jedenfalls ersteinmal das gesamte Array. Sie vergleicht das Referenzelement also mit allen anderen Werten des gesamten Arrays).
Wenn die Methode partition endet - was haben wir dann? Wir haben ein Element (das Referenzelement) an seine endgültige Position verschoben. Und wir haben das Array dadurch auch gleich in zwei Teile zerlegt: Alle Elemente die links vom Referenzelement stehen ([c]{2, 0, 1[/c])sind kleiner/gleich dem Referenzelement, die Elemente die rechts davon stehen ([c]{7, 8, 5, 4, 9, 6}[/c])sind größer/gleich. Und daraus können wir unschwer folgern, das wir die Elemente des linken Teilarrays gar nicht erst mit den Elementen des rechten Teilarrays zu vergleichen brauchen, und umgekehrt. Die linken Elemente sind ja sowieso allesamt kleiner/gleich den rechten Elementen. Wir können also jetzt ersteinmal hergehen und das linke Teilarray in aller Ruhe sortieren (ohne uns auch nur im geringsten um den rechten Teil des Arrays kümmern zu müssen). Und danach können wir in aller Ruhe das rechte Teilarray sortieren (ohne uns irgendwie um das linke Teilarray zu kümmern zu müssen).
Bleibt noch die Frage wie wir denn nun so ein Teilarray sortieren. Nun, man könnte sich ja ein beliebiges Element aus dem Teilarray als neues Referenzelement heraussuchen und dafür sorgen das es an seine endgültige Position wandert. Und dann könnte man das Teilarray links davon sowie das Teilarray rechts davon unabhängig voneinander sortieren. Zum Beispiel indem wir uns in den jeweiligen
neuen Teilarrays ein Referenzelement suchen und... so weiter und so fort.
Genau das ist die Idee des Quicksorts. Wir befördern ein Element an seine endgültige Position und zerlegen das Gesamtarray dadurch in zwei Teilarrays. In diesen Teilarrays schieben wir wieder jeweils ein Element an seine endgültige Position und zerlegen die bishereigen Teilarray dadurch auch wieder in jeweils zwei neue Teilarrays. Und so weiter. Dadurch erhalten wir zwar immer mehr zu sortierende Teilarrays, aber dafür werden diese auch immer kleiner. Bis sie irgendwann so klein sind, das ihre Sortierung trivial wird (z.B. wenn ein Teilarray nur noch zwei Elemente umfasst; diese beiden Elemente zu sortieren ist so einfach das wir das erledigen können ohne noch weiter zu unterteilen).
In deinem Programmcode wählt die Methode partition ein Referenzelement aus, schiebt es an seine aktuelle Position, und liefert diese Position als Rückgabewert zurück (m). Diese Position stellt die Grenze zwischen den beiden noch zu sortierenden Teilarrays dar. Anschließend wird zweimal _quicksort aufgerufen, einmal für das linke Teilarray (daher die Grenzen l und m-1) und einmal für das rechte Teilarray (welches die Grenzen m+1 und r hat). Die Methode _quicksort ruft nun partition auf um ein Element (aus dem beim Aufruf übergebenen Teilarray) an seine endgültige Position zu schieben und dadurchzwei neue Teilarrays zu schaffen. Für diese beiden neuen Teilarrays wird wiederum jeweils einmal _quicksort aufgerufen. Und so weiter. Durch diese rekursiven Aufrufe wird schlußendlich das gesamte Array sortiert.
Und wenn du bei diesen Erklärungen noch nicht eingeschlafen bist kannst du dir
hier auch mal anschauen wie das Vergleichen/Vertauschen von Werten und das Teilen des Arrays vonstatten geht.