• Keine Ergebnisse gefunden

Vorlesung Informatik 1

N/A
N/A
Protected

Academic year: 2022

Aktie "Vorlesung Informatik 1"

Copied!
21
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Vorlesung Informatik 1

Fachhochschule für Technik Esslingen Studiengang Wirtschaftsinformatik

Algorithmen

Dr. rer. nat. Andreas Rau

http://www.hs-esslingen.de/~rau

andreas.rau@hs-esslingen.de

(2)

In diesem Foliensatz sollen verschiedene Algorithmen genauer untersucht werden. Dabei soll für jeden Algorithmus Problem, Lösungsidee und technische Umsetzung betrachtet werden um so Einblicke zur Entwicklung eigener Lösung zu gewinnen.

Klassische Probleme der Informatik sind u.a.

Sortieren

Suchen

Weitere Übungen anhand des „interaktiven Labors“...

Inhalt

(3)

Sortieralgorithmen

(4)

Problemstellung

Sowohl Menschen als auch Maschine (vgl. Abschnitt über Suchen) tun sich mit sortierten Daten leichter. Man denke nur an ein unsortiertes Telefonbuch... Daher ist die Aufgabe, eine gegebene Datenmenge zu sortieren ein klassisches Problem der Datenverarbeitung.

Naturgemäß gibt es mehr als eine Lösung für dieses Problem. Jedoch sind nicht alle Lösungen gleich gut. Zur Bewertung kann man z.B. folgende Eigenschaften heranziehen:

Zeitverhalten

Wie schnell steigt die Rechenzeit in Abhängigkeit der Datenmenge an?

Schlechte Algorithmen brauchen für doppelt soviele Daten viermal solange...

Platzbedarf

Wie schnell steigt der Speicherplatz in Abhängigkeit der Datenmenge an?

Üblicherweise wird gefordert, daß ohne zusätzlichen Speicherplatz sortiert wird!

Stabilität

Damit ist gemeint, ob gleiche Elemente umsortiert werden oder nicht.

Dies ist z.B. relevant, wenn man hintereinander nach verschiedenen Kriterien sortiert.

Sortieren(1)

(5)

Anwendungsfälle

Sortierverfahren können in folgenden Anwendungsfällen eingesetzt werden:

Komplettes Sortieren einer ungeordneten Datenmenge

Umsortieren einer umgekehrt sortierten Datenmenge

Einsortieren eines neuen Datensatzes in eine bereits sortierte Menge

Der zweite Fall ist im Grunde ein pathologischer Sonderfall des ersten Falls bei dem

manche Sortierverfahren besonders schlecht funktionieren (wenn man den Fall erkennen würde, wäre es natürlich einfach).

Grundoperationen

Wie wir sehen werden werden zur Sortierung die folgenden Grundoperationen benötigt:

Zugreifen / Vergleichen

Vertauschen

Einfügen

Diese funktionieren mit unterschiedlichen Datenstrukturen unterschiedlich gut...

Sortieren(2)

(6)

Sortieren(3) Vorüberlegungen

Überlegen Sie kurz wie sie in folgenden Fällen selbst beim sortieren vorgehen (würden)

Sortieren von Karten beim Kartenspiel

Sortieren von Büchern / Filmen / CDs in einem Regal

Sortieren eines Briefen (Stapel) nach Eingangsdatum

Sortieren von ...

Praktische Übung

Führen sie nun folgende praktische Übung durch:

Eine DIN A4 Seite längs falten und reißen

Die Teile noch 2x falten und reißen um schließlich 8 Teile zu erhalten

Die 8 Teile mit „Zufallszahlen“ beschriften und mischen

Die oben überlegten Lösungsverfahren praktisch ausprobieren

(7)

Sortieren(4) Vorbereitung

Für die Evaluierung der verschiedenen Sortierverfahren werden wir Arrays mit Zufallszahlen verwenden. Zur Generierung soll die Klasse „Generator“ dienen.

public class Generator {

public static void printNumbers( int[] numbers) { boolean delim = false;

for ( int i : numbers) {

if ( delim) System.out.print( ", ");

System.out.printf( "%3d", i);

delim = true;

}

System.out.println();

}

public static int[] generateRandomNumbers( int n, int min, int max) { int[] numbers = new int[n];

for ( int i=0; i<n; ++i) {

numbers[i] = (int)(Math.random()*(max-min+1) + min);

}

return numbers;

}

// ...see next page

(8)

Sortieren(5)

// ...continued from previous page

public static int[] generateAscendingNumbers(int n, int min, int max, int jitter) { int[] numbers = new int[n];

for ( int i=0; i<n; ++i) {

min = min + (int)(Math.random()*jitter + 1);

numbers[i] = Math.min( min, max);

}

return numbers;

}

public static int[] generateDescendingNumbers(int n, int min,int max, int jitter) { int[] numbers = new int[n];

for ( int i=0; i<n; ++i) {

max = max - (int)(Math.random()*jitter + 1);

numbers[i] = Math.max( min, max);

}

return numbers;

}

public static void main( String[] args) {

printNumbers( generateRandomNumbers( 10, 1, 100));

printNumbers( generateAscendingNumbers( 10, 1, 100, 20));

printNumbers( generateDescendingNumbers( 10, 1, 100, 20));

} }

(9)

Sortieren(6) Rahmenprogramm

Der Rahmen zur Implementierung der Sortieralgorithmen sieht dann wie folgt aus:

public class SortBy<Verfahren> {

public static int[] sort( int[] numbers) { // Implementierung des Algorithmus

return numbers;

}

public static void main( String[] args) { System.out.println( "SortBy<Verfahren>\n");

int[] numbers = Generator.generateRandomNumbers( 10, 1, 100);

// int[] numbers = Generator.generateAscendingNumbers( 10, 1, 100, 20);

// int[] numbers = Generator.generateDescendingNumbers( 10, 1, 100, 20);

Generator.printNumbers( numbers);

System.out.println();

long t1 = System.currentTimeMillis();

sort( numbers);

long t2 = System.currentTimeMillis();

System.out.println();

Generator.printNumbers( numbers);

System.out.println( "\nDone in " + (t2-t1) + "ms");

}

}

(10)

Sortieren(7) Sortieren durch direktes Einfügen

Idee: Sortieren wie beim Kartenspielen

Wir vergleichen jedes Element mit allen Vorgängern und fügen es am richtigen Platz ein.

Dadurch wird der Anfang der Wertemenge vorsortiert und Stück für Stück ergänzt.

public static int[] sort( int[] numbers) { for ( int i=1; i<numbers.length; ++i) {

int x = numbers[i]; aktuelles Element „nehmen“

int j = i-1;

while ( j>=0) { // alle Vorgänger betrachten

if ( numbers[j]<=x) break; // wenn Vorgänger nicht größer abbrechen (=stabil) numbers[j+1] = numbers[j]; // sonst nachrücken und weiter

j--;

}

numbers[j+1] = x; // aktuelles Element „einfügen“

Generator.printNumbers( numbers); // Zwischenergebnis ausgeben }

return numbers;

}

Machen sie sich die Arbeitsweise des Algorithmus anhand der Ausgabe der Zwischenschritte klar. Spielen Sie anschließend verschiedene Szenarien durch.

ACHTUNG: Aussagekräftige Zeitmessungen nur bei auskommentierten Ausgaben.

(11)

Sortieren(8) Sortieren durch direktes Auswählen

Idee: Systematische Suche

Wir suchen nacheinander das kleinste, zweitkleinste, ... Element und fügen es am richtigen Platz ein. Dadurch wird die Wertemenge Stück für Stück final sortiert.

public static int[] sort( int[] numbers) { for ( int i=0; i<numbers.length-1; ++i) { int x = i; // aktuelles Element auswählen for ( int j=i+1; j<numbers.length; ++j) {

if ( numbers[j]<numbers[x]) x = j; // anderes Element auswählen }

// Gefundenes Element durch Austausch an richtige Position bringen int t = numbers[i];

numbers[i] = numbers[x];

numbers[x] = t;

Generator.printNumbers( numbers); // Zwischenergebnis ausgeben }

return numbers;

}

Machen sie sich die Arbeitsweise des Algorithmus anhand der Ausgabe der Zwischenschritte klar. Spielen Sie anschließend verschiedene Szenarien durch.

ACHTUNG: Aussagekräftige Zeitmessungen nur bei auskommentierten Ausgaben.

(12)

Sortieren(9)

Sortieren durch Wandern (aka Bubblesort)

Idee: Bei der Suche bereits kleinere Umstellungen vornehmen

Wir suchen nacheinander das größte, zweitgrößte, ... Element indem wir vom gegenüberliegenden Ende aus Schritt für Schritt vergleichen und uns „hochtauschen“.

public static int[] sort( int[] numbers) { for ( int i=numbers.length-1; i>0; --i) { for ( int j=0; j<i; ++j) {

if ( numbers[j]>numbers[j+1]) {

// Gefundenes Element durch Austausch wandern lassen int t = numbers[j];

numbers[j] = numbers[j+1];

numbers[j+1] = t;

} }

Generator.printNumbers( numbers); // Zwischenergebnis ausgeben }

return numbers;

}

Machen sie sich die Arbeitsweise des Algorithmus anhand der Ausgabe der Zwischenschritte klar. Spielen Sie anschließend verschiedene Szenarien durch.

ACHTUNG: Aussagekräftige Zeitmessungen nur bei auskommentierten Ausgaben.

(13)

Sortieren(10)

Sortieren durch „geniale Idee“ (aka Quicksort)

Idee: Tauschen über große Distanz mit rekursivem „teilen und herrschen“

public static int[] sort( int[] numbers, int l, int r) {

int x = numbers[(l+r)/2]; // "willkürliches" Vergleichselement wählen int i = l, j = r;

while (i<=j) {

while ( numbers[i]<x) i++; // linken Tauschpartner suchen while ( numbers[j]>x) j--; // rechten Tauschpartner suchen if (i<=j) { // Tausch durchführen

int t = numbers[i];

numbers[i] = numbers[j];

numbers[j] = t;

i++;

j--;

}

} // jetzt liegt Partitionierung in Teile<=k und Teile>=k vor System.out.printf( "%2d-%2d(%2d):", l, r, x);

Generator.printNumbers( numbers);

if (l<j) sort( numbers, l, j); // Teilintervall sortieren wenn nicht leer if (i<r) sort( numbers, i, r); // Teilintervall sortieren wenn nicht leer return numbers;

}

public static int[] sort( int[] numbers) {

return sort( numbers, 0, numbers.length-1); // Einstieg in Rekursion }

(14)

Sortieren(11)

Quicksort ist natürlich „starker Tobak“ und erschließt sich (wenn dann) nur nach mehrmaligem Durchdenken und/oder manuellem Nachvollziehen.

Festzuhalten ist jedoch, daß Quicksort zwar (im Mittel) der schnellste Algorithmus für zufällig sortierte Werte (daher der Name) jedoch beileibe nicht das Maß aller Dinge ist. So hat Quicksort die unangenehme Eigenschaft, in bestimmten Fällen besonders viel Zeit oder besonders viel Speicher zu benötigen (Details siehe Literatur).

Dabei spielt u.a. die Wahl des Vergleichselements eine besondere Rolle. Für das Sortieren kleiner Datenmengen ist Quicksort kaum schneller (und weniger „berechenbar“

als einfache Sortiermethoden).

Für den Anwendungsfall „Einfügen eines einzelnen Elements“ sind einfache Sortierverfahren bzw. geeignete Suchverfahren ohnehin die bessere Wahl.

(15)

Suchalgorithmen

(16)

Suchen(1) Problemstellung

Neben dem Sortieren ist Suchen die zweite klassische Aufgabe bei der elektronischen Datenverarbeitung. Die Sortierung ist sozusagen nur eine Vorstufe davon, da man in sortierten Daten schneller suchen kann. Bei der Bewertung von Suchalgorithmen zählt vor allem das

Zeitverhalten

Wie schnell steigt die Rechenzeit in Abhängigkeit der Datenmenge an?

Dagegen spielt der Platzbedarf i.d.R. keine Rolle da ja direkt in den Daten gesucht wird.

Wie hoch ist wohl der maximale Zeitbedarf im worst-case?

Grundoperationen

Beim Suchen gibt es im wesentlichen eine Grundoperation

Vergleichen

dies klingt zwar zunächst trivial, kann aber bei komplexen Objekten auch teuer sein!

(17)

Suchen(2) Anwendungsfälle

Von dem eigentlichen Grundproblem „finde einen gesuchten Wert in einer vorgegebenen Menge“ gibt es kleine Variationen:

prüfe, ob der gesuchte Wert enthalten ist

zähle, wie oft der gesuchte Wert enthalten ist

finde das erste Vorkommen des Werts (und liefere die Position zurück)

finde das nächste Vorkommen des Werts

finde das letzte Vorkommen des Werts

finde alle Vorkommen des Werts

Einige dieser Fragen lassen implizit die Beantwortung anderer Fragen zu. Welche?

Vorüberlegungen

Wie würden Sie in der realen Welt folgende Suchprobleme lösen

Suchen einer CD im Regal

Suchen eines Motivs in einer Diasammlung

Suchen einer Telefonnummer im Telefonbuch

Offensichtlich ist eine gewisse Ordnung / Sortierung hilfreich bei der Suche!

(18)

Suchen(3) Rahmenprogramm

Zur Untersuchung der Suchalgorithmen können wir wiederum Zufallszahlen verwenden.

Der Rahmen zur Implementierung der Suchalgorithmen sieht dann wie folgt aus:

public class SearchBy<Verfahren> {

public static int search( int[] numbers, int number) { // Implementierung des Algorithmus

return index;

}

public static void main( String[] args) {

System.out.println( "SearchBy<Verfahren>\n");

int[] numbers = Generator.generateRandomNumbers( 10, 1, 100);

int number = numbers[ (int)(Math.random()*10)]; // zufällige Zahl wählen long t1 = System.currentTimeMillis();

int index = search( numbers, number); // versuchen die Zahl wieder zu finden long t2 = System.currentTimeMillis();

Generator.printNumbers( numbers);

if ( -1 != index) {

System.out.printf( "%" + (5*index+3) + "s=%d(%d)", "^^^", number, index);

}

System.out.println( "\nDone in " + (t2-t1) + "ms");

}

}

(19)

Suchen(4) Lineare Suche

Idee: Jedes Element betrachten bis das gesuchte Element gefunden ist.

Voraussetzung: Man weiss nichts über die Elemente und deren Ordnung public static int search( int[] numbers, int number) { for ( int i = 0; i<numbers.length; ++i) {

if ( numbers[i]==number) { return i;

} }

return -1;

}

Bei der linearen Suche braucht man im worst-case n, im Mittel n/2 Vergleiche. Da man nichts über die durchsuchten Daten weiß, bleibt einem auch gar nichts anders übrig!

(20)

Suchen(5) Binäre Suche

Idee: Das gesuchte Element gezielt „einkreisen“ (teilen und herrschen, vgl. Zahlenraten) Voraussetzung: Die Elemente sind in bekannter Weise geordnet.

public static int search( int[] numbers, int number) { int lo = 0, hi = numbers.length-1;

do {

int index = (hi+lo)/2;

if ( numbers[index]<number) { lo = index+1;

continue;

}

if ( numbers[index]>number) { hi = index-1;

continue;

}

return index;

} while ( lo<=hi);

return -1;

}

Man schließt also mit Hilfe der Sortierung bei jedem Schritt möglichst viele Elemente aus.

Ordnung hat also große Vorteile! Sie muss aber vorhanden sein, sonst klappt's nicht!

(21)

Referenzen

Literaturhinweise:

[1] Niklaus Wirth, Algorithmen und Datenstrukturen, Teubner Verlag

[2] Robert Sedgewick, Algorithms in <your favorite language>, Addison Wesley

Links:

[1] http://de.wikipedia.org/wiki/Sortierverfahren

Analytischer Vergleich verschiedener Verfahren mit Links zu Detailbeschreibungen [2] http://www.ldv.ei.tum.de/media/files/lehre/gi/praktikum/interaktiv/sort/sort.html

Interaktive Animation von Sortieralgorithmen

[3] http://ivs.cs.uni-magdeburg.de/~dumke/EAD/Skript10.html Pseudocode Darstellung von Such- und Sortieralgorithmen [4] http://www-igm.univ-mlv.fr/~lecroq/string/

Algorithmen zum Stringvergleich (~Suche von Teilfolgen)

Referenzen

ÄHNLICHE DOKUMENTE

Diese kann sich naturgemäß nicht über Nacht einstellen, man muß schon etwas (Frei)zeit investieren!. Die Umstellung wird durch die Tatsache weiter erschwert, daß sich

Komplexere Styledefinitionen beziehen sich auf mehrere Tags, enthalten mehrere Eigenschaften oder nutzen die Schränken die betroffenen Tags durch Beschreibung der

● Datenelemente können eindeutig referenziert werden (z.B. über Pfad, ID). ● Datenelemente können weitere Eigenschaften haben

Daneben gibt es in Java aber auch noch Kommentare, die sowohl für den Menschen als auch den Computer gedacht sind:.. Kommentare zur Generierung von Dokumentation

Glücklicherweise muß man dies nicht manuell implementieren: Über das Interface Serializable können beliebige Klassen für die automatische Ein-/Ausgabe markiert

Während es im textbasierten Programm eine eigene Ablaufsteuerung (meist in Form einer Schleife) gibt, die Benutzereingaben wartet und diese verarbeitet, wartet

Fehler und die Leute die sie machen sind im allgemeinen nicht sehr beliebt?. ABER: Fehler sind nicht so schlimm, wie manche

Das Programm muss zu jedem Zeitpunkt lauffähig sein; keine Grossbaustelle Ein Mitarbeiter (der PL?) ist verantwortlich für das zusammenführen der Teile zu einem