01.03.2014 Aufrufe

13SS_6b_PG1_Algorithmen_Datenstrukturen_Suchen_Sortieren_Stud_01_21.pdf

13SS_6b_PG1_Algorithmen_Datenstrukturen_Suchen_Sortieren_Stud_01_21.pdf

13SS_6b_PG1_Algorithmen_Datenstrukturen_Suchen_Sortieren_Stud_01_21.pdf

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

<strong>Algorithmen</strong> und <strong>Datenstrukturen</strong> (Beispiele in C++)<br />

Reiner Nitsch<br />

8471<br />

reiner.nitsch@h-da.de


Such-<strong>Algorithmen</strong> – Lineare Suche<br />

Prinzip der linearen Suche:<br />

‣Betrachte jedes Element im Suchbereich<br />

‣Vergleiche jedes Element im Suchbereich mit dem Suchwert<br />

‣Wenn gefunden (Suchtreffer), gib Index oder Zeiger auf Suchtreffer zurück<br />

‣Wenn nicht gefunden (Suchfehler), gib Sentinel zurück.<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

int* find( int* pfirst, int* plast, int val ) {<br />

while( pfirst


Such-<strong>Algorithmen</strong> – Binäre Suche<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Nachteil der linearen Suche: langsam, weil Suche in kleinen Schritten<br />

Besser: Suche in großen Schritten<br />

Frage: Wie errät man eine Zufalls-Zahl zwischen 0 und 100 am schnellsten?<br />

2. Version des Suchalgorithmus: Binäre Suche<br />

Algorithmischer Kern<br />

Rateversuch: Mittlere Zahl aus (sortiertem) Suchbereichs<br />

wenn gleich: fertig<br />

sonst: links oder rechts weitersuchen<br />

int* binarySearchI( int* pfirst, int* plast, int val ) {<br />

//Binäre Suche (iterativ) im Bereich [pfirst, plast);<br />

// Vorbedingung: sortierte Elemente in Bezug auf operator<<br />

}<br />

int* pend = plast;<br />

while (pfirst


Aufwand von <strong>Algorithmen</strong> (Komplexität)<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Kriterien sind u.a.<br />

Speicheraufwand<br />

‣ für Programm/Algorithmus<br />

‣ für Daten<br />

Zeitaufwand<br />

‣ für Aufruf und Initialisierungen<br />

‣ für Wiederholungen<br />

statisch<br />

dynamisch, d.h. abhängig von Datenmenge<br />

statisch<br />

dynamisch<br />

Speicherkomplexität<br />

Zeitkomplexität<br />

Eine präzise detailreiche Bestimmung der Aufwände wird i.A nicht durchgeführt, weil dies<br />

‣ mathematisch oft nicht handhabbar ist<br />

‣ uninteressant ist: für Vergleichszwecke reicht auch ger. Detailierungsgrad<br />

Vereinfachungen (Abstraktionen) bei der Ermittlung des Zeitaufwandes<br />

Der tatsächliche Zeitaufwand ist immer prozessorabhängig.<br />

Um davon unabhängig zu werden, macht man folgende Vereinfachungen:<br />

‣ Jede Anweisung (Schleifen ausgenommen) benötigt den Zeitaufwand 1<br />

‣ Bei Wiederholungen/Schleifen sind wiederholten Anweisungen mit der Anzahl der Wiederholungen zu<br />

gewichten, die meist von der Anzahl n der Eingabedaten bestimmt ist.<br />

20.06.2<strong>01</strong>3 5


Aufwand von <strong>Algorithmen</strong> - Abstraktionen<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Wenn die Algorithmuslaufzeit T(n) nicht für alle Eingaben derselben Länge n gleich<br />

ist, sind folgende Grenzfälle interessant:<br />

der beste Fall (best case) T best<br />

der schlimmste Fall (worst case) T worst<br />

das Durchschnittsverhalten (average case) T avg<br />

O-Notation (auch Landau-Notation) der Laufzeitfunktion<br />

ist ein mathematisches Verfahren zur Einordnung der Komplexität von Funktionen für<br />

großes n.<br />

benennt lediglich aus einer Klasse gleich schnell wachsender Funktionen den einfachsten<br />

Repräsentanten als obere Schranke (Supremum). Meist reicht diese Abschätzung der<br />

Größenordnung, weil <strong>Algorithmen</strong> sich schon hier unterscheiden.<br />

gibt ein Maß für die Anzahl der Elementarschritte in Abhängigkeit von der Anzahl n der<br />

Eingabedaten an.<br />

20.06.2<strong>01</strong>3 6


Such-<strong>Algorithmen</strong> – Binäre Suche<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

1<br />

1<br />

1<br />

1<br />

1<br />

Lineare Suche<br />

1<br />

1<br />

int* find( int* pfirst, int* plast, int val ) {<br />

while( pfirst


Komplexität der binären Suche<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Aufwandsabschätzung für binäre Suche<br />

• Jede Iteration benötigt die Zeit 3<br />

• Jede Iteration halbiert den Suchbereich<br />

Nach dem 1. Halbieren enthält Suchbereich noch n/2 = n/2 1 Elemente<br />

Nach dem 2. Halbieren enthält Suchbereich noch n/4 = n/2 2 Elemente<br />

…<br />

Nach dem R-ten Halbieren enthält Suchbereich noch n/2 R Elemente<br />

• Worst case: Suche endet, wenn Suchbereich nur noch 1 Element enthält!<br />

n<br />

2 R = 1 R = log 2(n) Wiederholungen Zeitkomplexität T(n) = R(n)·3+2= log 2 (n) · 3 + 2<br />

d.h. die Zeitkomplexität wächst logarithmisch mit n<br />

Dies bringt man abkürzend durch die "Big-O"-Notation zum Ausdruck: Zeitkomplexität = O( log n )<br />

Ergebnis: In sortierten Reihen kann wesentlich schneller gesucht werden!<br />

Beispiel: Laufzeitvergleich<br />

lineare ↔ binäre Suche<br />

(gemessene Werte:<br />

Intel X86 Prozessor, 1,66 GHz,<br />

Debug-Konfiguration)<br />

n O(n) O(log n)<br />

1000 2,6 us 0,1 us = 0,033 us • 3<br />

10 6 2,6 ms 0,2 us = 0,033 us • 6<br />

10 9 2,6 s 0,3 us = 0,033 us • 9<br />

20.06.2<strong>01</strong>3 8


Beispiele zur Schätzung der Zeitkomplexität<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Laufzeit<br />

Anweisung Zeitkomplexität T(n) Big-O Typische <strong>Algorithmen</strong><br />

x=x+1;<br />

for (int i=1; i


Weitere Beispiele für O-Notation der Algorithmuslaufzeit<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Notation Bedeutung Anschauliche Erklärung Beispiele für Laufzeiten<br />

T(n) є O(1)<br />

ist konstant<br />

überschreitet einen konstanten Wert nicht<br />

(unabhängig vom Wert des Arguments).<br />

Nachschlagen des x-ten Elementes in einem<br />

Feld.<br />

T(n) є O(log n)<br />

wächst<br />

logarithmisch<br />

wächst ca. um einen konstanten Betrag,<br />

wenn sich das Argument verzehnfacht.<br />

Binäre Suche im sortierten Feld mit n<br />

Einträgen<br />

T(n) є O(√n)<br />

wächst wie die<br />

Wurzelfunktion<br />

wächst ungefähr auf das Doppelte, wenn<br />

sich das Argument vervierfacht<br />

naiver Primzahltest mittels Teilen durch<br />

jede Zahl ≤n<br />

T(n) є O(n)<br />

wächst linear<br />

wächst ungefähr auf das Doppelte, wenn<br />

sich das Argument verdoppelt.<br />

Suche im unsortierten Feld mit Einträgen<br />

(Bsp. Lineare Suche)<br />

T(n) є O(nlog n)<br />

hat super-lineares<br />

Wachstum<br />

Fortgeschrittenere <strong>Algorithmen</strong> zum<br />

<strong>Sortieren</strong> von Zahlen Mergesort, Heapsort<br />

T(n) є O(n 2 )<br />

wächst<br />

quadratisch<br />

wächst ungefähr auf das Vierfache, wenn<br />

sich das Argument verdoppelt<br />

Einfache <strong>Algorithmen</strong> zum <strong>Sortieren</strong> von<br />

Zahlen Selectionsort<br />

T(n) є O(n k )<br />

wächst<br />

polynomiell<br />

wächst ungefähr auf das Doppelte, wenn<br />

sich das Argument um eins erhöht<br />

Zahlenschloßprojekt T(n)=O(n 3 )<br />

T(n) є O(n!)<br />

wächst faktoriell<br />

wächst ungefähr um das n-fache, wenn<br />

sich das Argument um eins erhöht.<br />

Problem des Handlungsreisenden<br />

20.06.2<strong>01</strong>3 10


Warum ist die Zeitkomplexität eines Algorithmus so wichtig?<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Häufig ist die erste Idee, die HW zu beschleunigen.<br />

Aber: der Geschwindigkeitsvorteil ist dabei auf konstanten Faktor beschränkt<br />

Bessere HW ist zudem teuer, bzw. stößt an technische Grenzen<br />

Ein schneller Algorithmus auf einer langsamen Maschine wird immer schneller<br />

sein als ein langsamer Algorithmus auf einer schnellen Maschine!<br />

Supercomputers are for people too rich and<br />

too stupid to design efficient algorithms<br />

(Steven Skiena)<br />

20.06.2<strong>01</strong>3 11


<strong>Sortieren</strong><br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Für ein Feld von n Objekten gibt es n! Permutationen<br />

<strong>Sortieren</strong> ist ein Vorgang, der durch (möglichst wenige) paarweise Vergleiche von<br />

Objekten eine dieser Permutationen herausfiltert, in der die Objekte einer<br />

bestimmten Ordnungsrelation (z.B. größer, kleiner, …) genügen.<br />

Stabile Sortierung<br />

Beispiel:<br />

7<br />

2<br />

2<br />

3<br />

5<br />

5<br />

3<br />

7<br />

unsortiert sortiert<br />

Kommt ein Schlüsselwert<br />

mehrfach vor (Duplikate) ist<br />

die Sortierung nicht eindeutig:<br />

Ein Sortierverfahren, bei dem die<br />

Reihenfolge von Schlüsselduplikaten<br />

nach dem <strong>Sortieren</strong> unverändert ist,<br />

bezeichnet man als<br />

"Stabiles Sortierverfahren"<br />

1<br />

3<br />

3<br />

7<br />

7<br />

3<br />

1<br />

3<br />

1<br />

3<br />

3<br />

7<br />

sortiert unsortiert stabil sortiert<br />

Schlüsselwerte<br />

20.06.2<strong>01</strong>3 12


Sortierverfahren - Klassifizierungskriterien<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Zeitverbrauch<br />

‣ Anzahl Schlüsselvergleiche<br />

‣ Anzahl Vertauschungen<br />

‣ Sensibilität bezüglich Eingabeverteilung<br />

Zeitkomplexität<br />

Speicherplatzverbrauch (Programme u. Daten)<br />

Speicherkomplexität<br />

‣ Speicherplatzbedarf am geringsten für <strong>Sortieren</strong> am Ort ("in place" oder "in situ")<br />

Stabile Sortierverfahren, ändern die Reihenfolge von Duplikaten beim <strong>Sortieren</strong> nicht.<br />

Wie schnell kann man sortieren?<br />

Voraussetzung für jedes <strong>Sortieren</strong>: Auf den zu sortierenden Objekten muss eine Ordnung für<br />

die Schlüsselwerte definiert sein.<br />

Untere Komplexitätsschranke für Sortierverfahren:<br />

Satz: Jedes vergleichsbasierte Sortierverfahren für N Elemente benötigt im<br />

Mittel und im schlechtesten Fall eine Laufzeit von wenigstens<br />

T(N)O(N·log N) Vergleiche<br />

20.06.2<strong>01</strong>3 13


Sortierverfahren - Klassifizierung von Sortiertechniken<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

<strong>Sortieren</strong> durch<br />

L1<br />

Min. Element von L2<br />

1) Auswählen<br />

2) Einfügen<br />

sortiert<br />

sortiert<br />

3) Austauschen Elementare Sortierverfahren<br />

4) Zerlegen<br />

K i >K<br />

K<br />

K j


<strong>Sortieren</strong> durch Austauschen (exchange sort, bubble sort)<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Austauschen<br />

lokal<br />

Idee:<br />

Beginnend am Anfang der unsortierten<br />

Teilreihe werden jeweils Elementpaare<br />

gebildet.<br />

Die Elemente eines Paares werden<br />

verglichen und dann getauscht, wenn das<br />

größere Element näher am Anfang der<br />

Reihe liegt.<br />

Nach N-1 Schritten ist der 1. Sortierlauf<br />

beendet und das größte Element zum Ende<br />

der Reihe wie eine Blase "aufgestiegen" (<br />

Bubble Sort). Es bildet dort das 1. Element<br />

der teilsortierten Reihe.<br />

Der Vorgang wird mit der um ein Element<br />

kleineren unsortierten Teilreihe wiederholt.<br />

Nach N-1 solchen Sortierläufen ist der<br />

Sortiervorgang abgeschlossen.<br />

first 420 97 97 97 97<br />

97 420 420 420 420<br />

420 420 420 3<strong>01</strong> 3<strong>01</strong><br />

3<strong>01</strong> 3<strong>01</strong> 3<strong>01</strong> 420 35<br />

35 35 35 35 420<br />

last … … … … …<br />

teilsortierte Reihe unsortierte Reihe<br />

first 97 97 97 97<br />

420 420 3<strong>01</strong> 3<strong>01</strong><br />

3<strong>01</strong> 3<strong>01</strong> 420 35<br />

35 35 35 420<br />

420 420 420 420<br />

last … … … …<br />

Ist der Sortiervorgang stabil?<br />

ja<br />

20.06.2<strong>01</strong>3 15


Implementierung von Bubble-Sort<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

/* BubbleSort - Sorts a subsequence [pfirst,plast)<br />

@param pfirst pointer to first element of subsequence<br />

@param plast pointer to one-past-the-end element of the subsequence */<br />

// version 1 (with pointer)<br />

void bubbleSort( int* pfirst, int* plast ) {<br />

}<br />

for ( int* plastu=plast-1; plastu>pfirst; --plastu )<br />

for ( int* pp=pfirst ; pp


Aufwandsabschätzung für Bubble-Sort<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Zeitkomplexität<br />

<br />

<br />

AnzVgl . N 1 ( N 2) ... 1<br />

12 ... ( N 1)<br />

<br />

N 1<br />

k 1<br />

N N 2<br />

N N<br />

( 1)<br />

<br />

2 2 2<br />

<br />

2<br />

N N<br />

Anzahl Vertauschungen <br />

4 4<br />

<br />

<br />

<br />

<br />

<br />

Im Mittel halb so viele wie Vergleiche.<br />

Zusammenfassung<br />

k<br />

first 97 97 97 97<br />

teilsortierte Reihe<br />

in-place<br />

stabil<br />

Vertauschungen: O(N 2 ) im Mittel und im worst case; keine im best case.<br />

Vergleiche (Ver.2): O(N 2 ) im Mittel und im worst case; O(N) im best case.<br />

Aufwand (Anzahl Vergleiche) ist unabhängig von Eingabeverteilung.<br />

Wird in der Praxis kaum eingesetzt.<br />

420 420 3<strong>01</strong> 3<strong>01</strong><br />

3<strong>01</strong> 3<strong>01</strong> 420 35<br />

35 35 35 420<br />

420 420 420 420<br />

last … … … …<br />

unsortierte Reihe<br />

first 97 97 97 97<br />

420 420 3<strong>01</strong> 3<strong>01</strong><br />

3<strong>01</strong> 3<strong>01</strong> 420 35<br />

35 35 35 420<br />

420 420 420 420<br />

last … … … …<br />

20.06.2<strong>01</strong>3 17


<strong>Sortieren</strong> durch Auswahl (selection sort, MinSort, ExchangeSort)<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Idee:<br />

Auswahl des kleinsten Elementes im<br />

unsortierten Teil (L2) der Reihe<br />

Austausch mit dem ersten Element der<br />

unsortierten Teilreihe<br />

Die teilsortierte Reihe (L1) ist danach<br />

um 1 Element gewachsen. Die<br />

unsortierte Reihe enthält 1 Element<br />

weniger.<br />

Nach N solchen Durchläufen ist die<br />

Reihe sortiert.<br />

first 420 35 35 35 35<br />

420 420 97 97 97<br />

97 97 420 3<strong>01</strong> 3<strong>01</strong><br />

3<strong>01</strong> 3<strong>01</strong> 3<strong>01</strong> 420 420<br />

35 420 420 420 420<br />

last … … … … …<br />

teilsortierte Reihe unsortierte Reihe<br />

Auswählen<br />

L1 Min. Element von L2<br />

first<br />

firstu<br />

min<br />

last<br />

Ist der Sortiervorgang stabil?<br />

Beispiel: s. Abb. ( Key 420 )<br />

20.06.2<strong>01</strong>3 18


<strong>Sortieren</strong> durch Auswahl - Komplexität und Eigenschaften<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

// Algorithmus in Pseudocode<br />

prozedur selectionSort( a, first, last )<br />

[ a[first], a[last] ) : Bereich sortierbarer Elemente<br />

Variable: firstu:=first Position d. 1. Elem. der unsort. Reihe<br />

wiederhole<br />

Variable: min:= firstu<br />

für jede Position pos von firstu+1 bis last-1 wiederhole<br />

falls a[pos]


<strong>Sortieren</strong> durch Einfügen (insertion sort)<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Idee: Vorgehen wie beim <strong>Sortieren</strong> eines<br />

Kartenspiels.<br />

1. Starte mit oberster Karte den sortierten<br />

Stapel<br />

2. Nimm die jeweils nächste Karte vom<br />

unsort. Stapel<br />

3. Füge sie an der richtigen Stelle im<br />

sortierten Stapel ein<br />

In einem Array müssen die größeren<br />

Elemente um 1 Indexposition weiter<br />

rücken, um dem kleineren Einfügeelement<br />

Platz zu machen.<br />

Mit jedem Einfügeschritt wird der<br />

sortierte Stapel um 1 ein Element größer.<br />

Nach N-1 solchen Einfügeschritten ist der<br />

Sortiervorgang abgeschlossen.<br />

first 420 97 97 35 35<br />

97 420 420 97 97<br />

420 420 420 420 3<strong>01</strong><br />

35 35 35 420 420<br />

3<strong>01</strong> 3<strong>01</strong> 3<strong>01</strong> 3<strong>01</strong> 420<br />

last … … … … …<br />

teilsortierte Reihe<br />

unsortierte Reihe<br />

prozedur insertionSort( a, first, last )<br />

[ a[first], a[last] ) : Bereich sortierbarer Elemente<br />

pos: mögliche Einfügeposition<br />

posC: Position des nächsten Einfügekandidaten<br />

valC: Wert des nächsten Einfügekandidaten<br />

für jedes Element von posC=first+1 bis last-1 wiederhole<br />

pos = posC<br />

6 5 4 3 2 1 valC<br />

valC := a[posC]<br />

solange first


<strong>Sortieren</strong> durch Einfügen - Komplexität und Eigenschaften<br />

FB Informatik<br />

Prof. Dr. R.Nitsch<br />

Worst Case bei invers sortierter Reihe<br />

Max. Anzahl der Vergleiche:<br />

12 ... ( N 1)<br />

<br />

( 1)<br />

<br />

2 2 2<br />

2<br />

N N N N<br />

N 1<br />

<br />

k 1<br />

Max. Anzahl der Verschiebungen:<br />

12 ... ( N 1) N( N 1)/ 2<br />

k<br />

first 420 97 97 35 35<br />

97 420 420 97 97<br />

420 420 420 420 3<strong>01</strong><br />

35 35 35 420 420<br />

3<strong>01</strong> 3<strong>01</strong> 3<strong>01</strong> 3<strong>01</strong> 420<br />

last … … … … …<br />

teilsortierte Reihe unsortierte Reihe<br />

Best Case bei sortierter Reihe<br />

Min. Anzahl der Vergleiche: 1 1 ... 1N<br />

1<br />

Min. Anzahl der Verschiebungen:<br />

0<br />

Vorteilhaft bei fast sortierten Reihen:<br />

In-place-Verfahren, stabil<br />

20.06.2<strong>01</strong>3 21

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!