Beruflich Dokumente
Kultur Dokumente
Java16 - Suchen Und Sortieren
Java16 - Suchen Und Sortieren
Lernziele
Algorithmen fr lineare und binre Suche erklren und anwenden knnen. Die Begriffe Komplexitt und Ordnung eines Algorithmus kennen. Algorithmen fr die Sortierverfahren Bubble-Sort, Insertion-Sort und Quick-Sort erklren knnen.
16.1 Suchverfahren
Das Suchen von Informationen in Informationsbestnden gehrt zu den hufigsten Aufgaben, die mit Computersystemen ausgefhrt werden. Oft ist die gesuchte Information eindeutig durch einen Schlssel identifizierbar. Schlssel sind in der Regel positive ganze Zahlen (z.B. Artikelnummer, Kontonummer etc.) oder alphabetische Schlssel (z.B. Nachname, Firmenname usw.). Von dem Schlssel gibt es meist eine Referenz auf die eigentlichen Informationen. Die Suchverfahren knnen Kategorien zugeordnet werden: Elementare Suchverfahren: Es werden nur Vergleichsoperationen zwischen den Schlsseln ausgefhrt. Schlssel-Transformationen (Hash-Verfahren): Aus dem Suchschlssel wird mit arithmetischen Operationen direkt die Adresse von Datenstzen berechnet. Suchen in Texten: Suchen eines Musters in einer Zeichenkette.
16.1.1
Lineare Suche
Die lineare bzw. sequentielle Suche wird immer dann angewendet, wenn die Schlssel in ungeordneter Folge in einer Liste abgelegt sind. Lineare Suche: Die Elemente der Liste werden der Reihe nach mit dem Suchschlssel verglichen, bis das passende Element gefunden wird oder das Ende der Liste erreicht ist. Beispiel:
a[ i ]
10/2008
Als Ergebnis der Suche kann entweder die Position des gesuchten Elements zurckgegeben werden oder auch nur die Information ob das gesuchte Element in der Liste enthalten ist. Das Struktogramm zeigt eine Funktion, die bei erfolgreicher Suche die Schlsselposition zurckgibt, deren Wert zwischen 0 und (n 1) liegt. Ist das gesuchte Element nicht im Feld enthalten, liefert die Funktion den Wert n zurck.
lineareSuche( int a[ ], int n, int k ) int i = 0 while( i < n && k != a[ i ] ) i=i+1 return i
Aufwandsbetrachtung
Unter der Komplexitt eines Algorithmus versteht man den zu seiner Durchfhrung erforderlichen Aufwand an Betriebsmitteln wie Rechenzeit und Speicherplatz. Die asymptotische Zeitkomplexitt wird als Ordnung bezeichnet und durch ein groes O ausgedrckt: O(n). Wenn ein Algorithmus Eingabedaten des Umfangs n verarbeitet, und der Zeitaufwand linear ist, besitzt der Algorithmus die Ordnung n. Seine Zeitkomplexitt ist dann proportional n. Fr die lineare Suche in einer Liste gilt: Enthlt die Liste n Elemente, dann werden im schlechtesten Fall n Schlsselvergleiche fr eine erfolgreiche Suche bentigt. Nimmt man an, dass die Verteilung der Schlssel gleichwahrscheinlich ist, dann ist zu erwarten, dass fr eine erfolgreiche Suche im Mittel
1 n
i =
i=1
n +1 2
16.1.2
Binre Suche
Liegen die Schlssel geordnet in einer linearen Liste vor, kann eine binre Suche durchgefhrt werden. In einem sortierten Feld kann man deutlich schneller suchen. Binre Suche: Man vergleicht zunchst den Suchschlssel mit dem Element in der Mitte des Feldes. Ist der Suchschlssel kleiner als das mittlere Element, setzt man die Suche im unteren Teilfeld fort. Ist der Suchschlssel grer als das mittlere Element, wird die Suche im oberen Teilfeld fortgefhrt. Im ausgewhlten Teilfeld vergleicht man nun den Suchschlssel wieder mit dem mittleren Element des Teilfeldes. Gegebenenfalls muss das Teilfeld erneut halbiert und die Suche nach dem beschrieben Verfahren fortgesetzt werden, bis das gesuchte Element gefunden ist oder nur noch ein Element brig bleibt.
C. Endre
2 / 14
10/2008
Index:
0 2
1 5
2 6
3 8
4 13
5 16
6 19
7 27
8 29
9 33
10 47
11 52
12 57
13 59 low = 0, high = 13 m=6 low = 0, high = 5 m=2 low = 3, high = 5 m=4 low = 3, high = 3 m=3
13
16
13
16
Index:
0 2
1 5
2 6
3 8
4 13
5 16
6 19
7 27
8 29
9 33
10 47
11 52
12 57
13 59 low = 0, high = 13 m=6 low = 7, high = 13 m = 10 low = 11, high = 13 m = 12 low = 11, high = 11 m = 11
27
29
33
47
52
57
59
52
57
59
52
C. Endre
3 / 14
10/2008
Der Suchalgorithmus kann sowohl rekursiv als auch iterativ formuliert werden. Die folgenden Struktogramme zeigen mgliche Formulierungen einer rekursiven sowie einer iterativen Funktion binSuche.
int binSuche( int a[ ], int k, int low, int high ) int m = (low + high) / 2 ja ja k = a[ m ] k < a[ m ] return binSuche(a, k, low, m - 1)
Rekursive Formulierung der binren Suche
nein
return m
ja
int binSuche( int a[ ], int n, int k ) int m int low = 0 int high = n - 1 while( low <= high) m = ( low + high ) / 2 ja k = a[ m ] k > a[ m ] low = m + 1 return -1
Iterative Formulierung der binren Suche
nein nein
return m
ja
high = m - 1
Aufwandsbetrachtung
Entscheidend fr den Aufwand ist die Anzahl der notwendigen Halbierungen, die natrlich von der Anzahl der Feldelemente abhngt. Im schlechtesten Fall sind so viele Halbierungen vorzunehmen, bis nur noch ein Element zu betrachten ist. Der Aufwand fr eine binre Suche ist durch die maximale Anzahl der Halbierungen des Feldes begrenzt.
0 n
1 n/2
2 n/4
3 n/8
C. Endre
4 / 14
10/2008
Da die Mindestgre des zu betrachtenden Teilfeldes 1 sein muss, ergibt sich die folgende Ungleichung:
n 2k
1.
Lst man diese Ungleichung durch Logarithmieren nach k auf, ergibt sich fr die Anzahl der Halbierungen:
k log2 (n)
Das gesuchte Element ist also nach maximal log2(n) Halbierungsschritten gefunden.
Binre Suche:
16.2 Sortieren
In vielen Anwendungen muss eine Folge von Objekten in eine bestimmte Reihefolge gebracht werden. Als Beispiel sei hier auf ein Telefonverzeichnis hingewiesen, in dem die Eintrge alphabetisch nach Namen zu sortieren sind. Bei kaufmnnisch-administrativen Anwendungen werden beispielsweise 25 % der Computerzeit fr Sortiervorgnge bentigt. Daher wurde intensiv nach effizienten Sortieralgorithmen gesucht, die sich nach folgenden Kriterien klassifizieren lassen: Zeitverhalten Interne vs. externe Sortierung, d.h. passen die zu sortierenden Schlssel alle in den Arbeitsspeicher oder nicht. Arbeitsspeicherverbrauch, d.h. wird zustzlicher Speicherplatz auer dem Platz fr die Schlssel bentigt. Stabiles vs. instabiles Verhalten, d.h. die Reihenfolge von Elementen mit gleichem Sortierschlssel wird whrend des Sortierens nicht vertauscht. Stabilitt ist oft erwnscht, wenn die Elemente bereits nach einem zweitrangigen Schlssel geordnet sind (z.B. Name, Vorname) Sensibilitt bezogen auf die Eingabeverteilung, d.h. verndert sich das Zeitverhalten, wenn die Eingabefolge bereits sortiert oder vollstndig unsortiert ist. Allgemeines vs. spezielles Verhalten, d.h. wird nur eine lineare Ordnung auf der Menge der Schlssel vorausgesetzt oder mssen die Schlssel von spezieller Gestalt sein. Anhand dieser Kriterien ist fr ein gegebenes Sortierproblem eine geeignete Auswahl zu treffen. Das Hauptkriterium ist natrlich das Zeitverhalten. Dazu gilt folgender Satz:
Kein Sortierverfahren kommt mit weniger als n log2( n ) Vergleichen zwischen Schlsseln aus.
C. Endre
5 / 14
10/2008
Die folgende Abbildung gibt einen berblick ber bekannte Sortierverfahren, die nach ihrem Zeitverhalten klassifiziert sind.
Sortierverfahren
Elementare Verfahren Schlsselvergleiche: O(n) = n (fr zufllig sortierte Folgen) Sortieren durch Auswahl
2
(selection sort)
Mischsortieren
(mergesort)
Quicksort
(insertion sort)
(Heapsort)
16.2.1
Bubble-Sort
Bubble-Sort: Durchlaufe das Feld in aufsteigender Richtung. Betrachte dabei immer zwei benachbarte Elemente. Wenn die zwei benachbarten Elemente nicht in aufsteigender Ordnung sind, vertausche sie. Nach dem ersten Durchlauf ist auf jeden Fall das grte Element am Ende des Feldes. Wiederhole den obigen Verfahrensschritt so lange, bis das Feld vollstndig sortiert ist. Dabei muss jeweils das letzte Element des vorherigen Durchlaufs nicht mehr betrachtet werden, da es schon seine endgltige Position gefunden hat.
Beispiel:
0 320 1 178 2 86 3 207 4 59
178
320
86
207
59
178
86
320
207
59
1. Durchgang
178
86
207
320
59
178
86
207
59
320
C. Endre
6 / 14
10/2008
178
86
207
59
320
86
178
207
59
320 2. Durchgang
86
178
207
59
320
86
178
59
207
320
86
178
59
207
320
86
178
59
207
320
3. Durchgang
86
59
178
207
320
86
59
178
207
320 4. Durchgang
59
86
178
207
320
Der Name Bubble-Sort rhrt daher, dass man das Wandern des grten Elements ganz nach rechts mit dem Aufsteigen von Luftblasen vergleichen kann. Der Algorithmus kann folgendermaen mit einem Struktogramm formuliert werden:
void bubbleSort( int a[ ], int n ) int temp for( int i = n - 1; i > 0; i-- ) for( int k = 0; k < i; k++ ) ja temp = a[ k ] a[ k ] = a[ k + 1 ] a[ k + 1 ] = temp
Bubble-Sort
a[ k ] > a[ k + 1 ] nein
C. Endre
7 / 14
10/2008
Aufwandsbetrachtung
Strukturell besteht der Bubble-Sort-Algorithmus aus einem Kern, der in zwei Schleifen eingebettet ist. Die Laufzeit des Kerns hngt natrlich davon ab, ob eine Vertauschung durchzufhren ist oder nicht. Im gnstigsten Fall (best case) ist das Feld bereits sortiert und es findet keine Vertauschung von Elementen statt. Im ungnstigsten Fall (worst case) erfolgt jedoch bei jedem Kerndurchlauf eine Vertauschung. Wenn wir eine zufllige Verteilung der Daten annehmen, knnen wir davon ausgehen, dass in etwa der Hlfte aller Kerndurchlufe eine Vertauschung durchzufhren ist. Der Kern wird also bei zuflliger Verteilung eine mittlere Laufzeit haben, die etwa die Hlfte der zur Vertauschung von zwei Elementen bentigten Rechenzeit ausmacht. Der Wert dieser Rechenzeit ist natrlich abhngig von der Plattform, auf der der Algorithmus abluft, sowie von dem Datentyp der Elemente. Strings oder Objekte bentigen eine wesentlich lngere Rechenzeit zur Vertauschung als elementare Datentypen. Unter der oben gemachten Annahme einer mittleren Rechenzeit fr den Algorithmuskern lsst sich die Komplexitt des Algorithmus nach folgender berlegung berechnen: Beim ersten Durchlauf durch das Feld luft die Laufvariable k der inneren Schleife von 0 bis n-2. Die innere Schleife wird also n-1 mal durchlaufen. Beim zweiten Durchlauf wird die innere Schleife nur noch n-2 mal durchlaufen. Beim dritten Durchlauf sind es nur noch n-3 Lufe durch die innere Schleife. Beim letzten Durchlauf wird die innere Schleife schlielich nur noch einmal durchlaufen. Daraus ergibt sich fr die Summe S der Lufe durch den Kern:
S = (n 1) + (n 2) + (n 3) + . . . + 3 + 2 + 1 =
i
i =1
n 1
Zur Berechnung der Summe verdoppeln wir beide Seiten der Gleichung:
2 S = (n 1) + (n 2) + (n 3) + K + 1 + 2 + 3
2 S = (n 1) n S= (n 1) n 2
+ K + (n 3) + (n 2) + (n 1)
Formel
folgt,
dass
der
Bubble-Sort-Algorithmus
ein
quadratisches
O(n) = n2
16.2.2
Insertion-Sort
Insertion-Sort ist ein Sortierverfahren, das so arbeitet wie wir Spielkarten auf der Hand sortieren. Insertion-Sort: Die erste Karte ganz links ist sortiert. Wir nehmen die zweite Karte und stecken sie, je nach Gre, vor oder hinter die erste Karte. Damit sind die beiden ersten Karten relativ zueinander sortiert. Wir nehmen die dritte Karte und schieben sie solange nach links, bis wir an die Stelle kommen, an der sie passt. Dort stecken wir sie hinein. Fr alle weiteren Karten verfahren wir der Reihe nach ebenso.
C. Endre
8 / 14
10/2008
In einem Array funktioniert das natrlich nicht ganz so leicht wie in einem Kartenspiel, da wir nicht einfach ein von rechts kommendes Element dazwischen schieben knnen. Dazu mssen zunchst alle bersprungenen Elemente nach rechts aufrcken, um fr das einzusetzende Element Platz zu machen.
0 320 1 178 2 86 3 207 4 101 unsortiertes Feld
320 178
86
207
101
1. Durchlauf
178
320 86
207
101
2. Durchlauf
86
178
320 207
101
3. Durchlauf
86
178
207 101
320
4. Durchlauf
86
101
178
207
320
sortiertes Feld
void insertionSort( int a [ ], int n ) int element, i, j for( i = 1; i < n; i++ ) element = a[ i ] j=i while( j > 0 && element < a[ j - 1 ] ) a[ j ] = a[ j - 1 ] j=j-1 a[ j ] = element
Insertion-Sort
C. Endre
9 / 14
10/2008
Aufwandsbetrachtung
Beim Insertion-Sort-Verfahren haben wir zwei ineinander verschachtelte Schleifen zu analysieren. Hierbei wird jedoch die innere Schleife ber eine zustzliche Bedingung (element < a[ j 1 ]) gesteuert. Bei zufllig verteilten Daten knnen wir davon ausgehen, dass diese Bedingung im Mittel bei der Hlfte des zu durchlaufenden Indexbereichs erfllt ist, die Schleife also im Durchschnitt auf halber Strecke abgebrochen werden kann. Bezeichnen wir die Laufzeit der inneren Schleife mit cins2 und die Laufzeit der ueren Schleife mit cins1, so ergibt sich die folgende Formel fr das Laufzeitverhalten von Insertion-Sort:
t(n) =
n 1 i =1
n 1
c + ins1 i=1
+
c
j =1
i/2
ins 2
t(n) =
ins1
i c ins2 2
c ins 2 2
t(n) = c ins1(n 1) +
i
i=1
n 1
n (n 1) 4
Auch hier haben wir wieder asymptotisch quadratisches Verhalten. Insertion-Sort: O(n) = n2
16.2.3
Quicksort
Das Quicksort-Verfahren wurde 1960 von C.A.R. Hoare erfunden ist eines der schnellsten Sortierverfahren fr Felder, die weitgehend unsortiert sind. Der Grundgedanke von Quicksort verfolgt die Divide-and-Conquer-Strategie: eine Folge wird durch Zerlegen in kleinere Teilfolgen sortiert. Quicksort: Zu Beginn wird in dem zu sortierenden Feld ein als Pivotelement (Angelpunkt) bezeichnetes Element beliebig gewhlt. In einem Durchlauf werden dann die Feldelemente so miteinander vertauscht, dass am Ende des Durchlaufs das Pivotelement das Feld in ein linkes Teilfeld und ein rechtes Teilfeld zerlegt. Alle Elemente des linken Teilfeldes sind kleiner oder gleich dem Pivotelement, die Elemente des rechten Teilfeldes sind grer oder gleich dem Pivotelement. Damit hat das Pivotelement seine endgltige Position in dem Feld eingenommen. Mit den beiden Teilfeldern wird nun in gleicher Weise verfahren, bis ein Teilfeld nur noch ein oder gar kein Element mehr enthlt und somit sortiert ist.
C. Endre
10 / 14
10/2008
Beispiel: Das Feld a[ ] mit 10 Elementen ist zu sortieren. In der Folge wird das Element in der Feldmitte (a[m] = 60) als Pivotelement fr eine Aufteilung der Folge in zwei Teilfolgen ausgewhlt.
0 76 1 7 2 58 3 88 4 60 5 41 6 82 7 77 8 49 9 86
Als nchstes wird die Folge von links durchsucht, bis ein Element gefunden wird, das grer als das Pivotelement oder das Pivotelement selbst ist. Das ist bereits bei a[0] = 76 der Fall. Von rechts wird die Folge durchsucht, bis ein Element gefunden wird, das kleiner als das Pivotelement oder das Pivotelement selbst ist. Die Suche hlt bei a[8] = 49 an. Die Elemente a[0] und a[8] werden anschlieend vertauscht.
0 76 Suche von links Elemente vertauschen 1 7 2 58 3 88 4 60 5 41 6 82 7 77 8 49 9 86 Suche von rechts
Die Suche wird von links mit dem Index 1 und von rechts mit dem Index 7 fortgesetzt. Die nchsten Elemente, die vertauscht werden sind im linken Teilfeld a[3] = 88 und im rechten Teilfeld a[5] = 41.
0 49 1 7 2 58 3 88 4 60 5 41 6 82 7 77 8 76 9 86
Der linke Suchindex wird auf 4 gesetzt. Der rechte Index erhlt ebenfalls den Wert 4. Die Suchbereiche berschneiden sich damit und der Durchlauf wird beendet. Das Pivotelement hat seinen endgltigen Platz erreicht. Im linken Teilfeld befinden sich nur noch Werte, die kleiner als der Pivot a[4] sind. Die Werte im rechten Teilfeld sind grer als der Pivot.
0 49 1 7 2 58 3 41 4 60 5 88 6 82 7 77 8 76 9 86
Die beiden Teilfelder werden nun rekursiv nach demselben Verfahren sortiert. Sortierung des linken Teilfelds a[0] . . . a[3]: Rekursionsebene 1
0 49 1 7 2 58 3 41
Als Pivot wird a[1] festgelegt. Die Suche von links ergibt, dass a[0] grer als das Pivotelement ist. Der rechte Index luft bis zum Pivotelement, da kein Element im rechten Feld kleiner als der Pivot ist. a[0] und der Pivot a[1] werden getauscht. Die Suchbereiche berschneiden sich, das Pivotelement hat seine endgltige Position im Feld bei a[0] erreicht. Das linke Teilfeld ist leer. Das rechte Teilfeld a[1]...a[3] wird in der nchsten Rekursionsebene bearbeitet
0 7
1 49
2 58
3 41
C. Endre
11 / 14
10/2008
Rekursionsebene 2
1 49
2 58
3 41
Das Pivotelement wird aus der Feldmitte (a[2]) gewhlt. Das Element a[3] des rechten Feldes wird mit dem Pivot vertauscht, da es kleiner ist.
1 49
2 41
3 58
Es kommt wieder zu einer berschneidung der Suchbereiche von links und rechts. Der Durchlauf wird abgebrochen. Das linke Teilfeld a[1]...a[2] wird in der nchsten Rekursionsebene sortiert. Das Element a[1] wird als Pivot gewhlt. Die Elemente werden vertauscht.
Rekursionsebene 3
1 49
2 41
1 41
2 49
Da das linke Teilfeld nur ein Element enthlt, ist es sortiert. Das rechte Teilfeld ist leer. Damit ist die gesamte Teilfolge a[0]...a[3] links des ersten Pivotelements a[4] sortiert.
5 76
6 82
7 77
8 88
9 86
5 76
6 77
7 82
8 88
9 86
Die Suchbereichberschneidung beendet den Durchlauf. Das linke Teilfeld besteht nur noch aus einem Element (a[5]) und ist deshalb sortiert. Das Element a[6] befindet sich ebenfalls an seiner endgltigen Position. Das rechte Teilfeld a[7]...a[9] wird in der nchsten Rekursionsebene sortiert. Als Pivot wird wieder die Feldmitte gewhlt (a[8])
Rekursionsebene 2
7 82
8 88
9 86
7 82
8 86
9 88
Das Pivotelement hat seinen Platz erreicht. Die linke Teilfolge wird wieder rekursiv sortiert.
C. Endre
12 / 14
10/2008
Rekursionsebene 3
7 82
8 86
a[7] wird als Pivot gewhlt. Die Suchbereiche berschneiden sich. Die Elemente sind sortiert
nein
nein
nein
Aufwandsbetrachtung
Wenn wir eine zentrierte Lage des Pivots unterstellen, erfolgt eine fortlaufende Halbierung der Teilfelder, so dass das Feld mit log2 n Halbierungen sortiert ist. Um jedes Element mit dem Pivot zu vergleichen, sind n1 Vergleiche und im Mittel n/2 Vertauschungen notwendig. Daraus ergibt sich im Mittel ein Aufwand von Quicksort:
C. Endre
O(n) = n * log2 n
13 / 14 10/2008
Beschreibung Lexikalischer Vergleich zweier Strings: Bei einem lexikalischen Vergleich werden die Zeichen paarweise von links nach rechts verglichen. Tritt ein Unterschied auf oder ist einer der Strings beendet, wird das Ergebnis ermittelt. Ist das aktuelle String-Objekt kleiner als s, wird ein negativer Wert zurckgegeben. Ist es grer, wird ein positiver Wert zurckgegeben. Bei Gleichheit liefert die Methode den Rckgabewert 0.
equals(String s) equalsIgnoreCase(String s)
Prfen auf Gleichheit: Die Methoden liefern true, wenn das aktuelle String-Objekt und der Parameter s inhaltlich gleich sind.
Beispiel: String name1 = Adam; String name2 = Eva; name1.compareTo(name2) liefert -1, weil Adam im Lexikon vor Eva steht.
C. Endre
14 / 14
10/2008