• Keine Ergebnisse gefunden

Dipl.-Inf., Dipl.-Ing. (FH) Michael Wilhelm

N/A
N/A
Protected

Academic year: 2021

Aktie "Dipl.-Inf., Dipl.-Ing. (FH) Michael Wilhelm"

Copied!
53
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Programmierung 1 Studiengang MI / WI

Dipl.-Inf., Dipl.-Ing. (FH) Michael Wilhelm

Hochschule Harz

FB Automatisierung und Informatik

mwilhelm@hs-harz.de

http://mwilhelm.hs-harz.de

Raum 2.202

Tel. 03943 / 659 338

(2)

Inhalt der Vorlesung

Überblick:

Erste Beispiele, Interaktion

elementare Datentypen

Variablen und Kontrollstrukturen

Arrays und Funktionen

Objekte und Methoden, Interface

Rekursion, Suchen, Sortieren

Algorithmen und Pseudocode

Laufzeitverhalten

Simulation

Bibliotheken

Folien basierend auf Daniel Schiffman “Learning Processing” und Donald W. Smith

Grundlegende Algorithmen und Methoden:

Suchen und Sortieren

Hashing

Rekursion

Graphen

Dynamische

Programmierung

Von Processing zu Java

(3)

Kapitel

Rekursion

Definition

Fakultät

Fibonacci

m über n

Suchen

• Lineares Suchen

• Intervallhalbiereungsverfahren

Sortieren

(4)

Rekursion

Berechnung der Fakultät;

int f=0;

int n=3;

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

f=f*i;

}

System.out.println("Ergebnis: "+f);

(5)

Rekursion

Berechnung der Fakultät;

int f=1;

int n=3;

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

f=f*i;

}

System.out.println("Ergebnis: "+f);

(6)

Rekursion

Besser wäre die Umsetzung mittels der mathematischen Notation:

n!

1 falls n=0

1 falls n=1

n*(n-1)! sonst

(7)

Rekursion

rekursiv definierte Funktionen (Beispiele):

a) Fakulatät n! = n * (n-1)! falls n > 1, 1! = 0! = 1

Benutzung

Anzahl der Möglichkeiten n unterscheidbare Elemente anzuordnen

b) Fibonacci-Folge: f(n) = f(n-1) + f(n-2) falls n > 1, f(1) = 1,

f(0) = 0

Benutzung

Wachstum (Wachstum einer Kaninchenpopulation) Abstand der Blätter

Grundlegende Schritte der Rekursion:

(8)

Rekursive Implementierung der Fakultät

long calcFakulteat2(int n) { long result = 1;

if(n > 1) {

result = n * calcFakulteat2(n-1);

}

else if (n < 0) { result = 0;

}

return result;

}

Fragen:

Was passiert in calcFakultaet2 für größere Werte von n?

(9)

Zwei Processing-Beispiele zur Rekursion:

Baum, Koch´sche Schneeflocke

(10)

Rekursive Implementierung der Fibonacci-Folge

long calcFibonacci2(int n) { long result = 0;

if(n > 1) { // Verhindert eine unendliche Rekursion

result = calcFibonacci2(n-1)+calcFibonacci2(n-2);

} else if(n == 1) { result = 1;

}

return result;

}

Weshalb ist diese rekursive Implementierung keine gute Idee?

(11)

Fibonacci-Funktion wird 2 mal rekursiv aufgerufen.

Insgesamt für das

Argument n also 2n+1 mal.

Dabei werden dieselben Werte

mehrfach berechnet.

Beispielrechner:

Taktfrequenz 2,8 GHz

Rekursive Implementierung der Fibonacci-Folge

n Java Zeit (iterativ)

Java Zeit

C# Delphi C / C++

20 1000 ns 0 ms 0 ms 0 ms 0 ms

30 1000 ns 16 ms 0 ms 16 ms 7 ms

35 1000 ns 46 ms 0,187 s 0,109 s 0,080 s 40 1000 ns 0,6 sec 1,8 sec 0,952

sec

1,02 s 45 1000 ns 6,7 sec 29,1 sec 12,2 sec 14,2 s 50 1000 ns 1:47

min

5:40 min 2:54 min

2:40 min 55 1000 ns 21 min 01:05:52 34:13

min 60 1000 ns 4 Std

70 1200 ns Jahre

(12)

Fibonacci ohne Rekursion

Grundlegende Idee der dynamischen Programmierung:

Speichere

Zwischenergebnisse, falls Sie später

nochmals benutzt werden können.

public class Fibonacci { private long[] value = null;

private final int MAX = 100;

public long fib(int n) { long result = -1;

if(value == null) {

value = new long[NVALS];

value[0] = 0;

value[1] = 1;

for(int i=2; i<NVALS; i++) {

value[i] = value[i-1] + value[i-2];

} // for } // if

if(n < NVALS) { result = value[n];

}

return result;

(13)

Berechnung von k aus n

Die Anzahl M der Möglichkeiten beim Ziehen von k

Elementen aus einer Gesamtheit von n Elementen ist gegeben durch:

=

= !

! · − ! = · − 1 · − 2 … · ( − + 1) − · − + 1 ·. . .· 2 · 1

Weshalb ist diese Formel nicht gut für eine Computer- Implementierung geeignet?

Die Rekursionsformel

=

+

,

auch als Pascal´sches Dreieck bekannt, ist besser

geeignet. Beachte, dass

=

= 1

(14)

Pacal‚sche Dreieck

(15)

Datenstrukturen: Stack (Stapel-/Kellerspeicher)

Ein Stapel kann eine beliebige Menge von Elementen

speichern.

Dabei kann ein neues Element immer nur oben auf den

bestehenden Stapel darauf gelegt werden (push).

Ebenso kann ein Element nur von dort entfernt werden (pop).

Anwendungen

(16)

Anwendung eines Stacks

Java/Processing teilt jedem Programm Speicher (genannt Heap) und einen Stack zu.

Der Stack dient als Speicher für lokale Variablen

Was passiert bei einem Methoden-/Funktionsaufruf?

public void test1() { int m = add(3, 4);

System.out.println(m);

}

public int add(int a, int b) { int c=a+b;

return c;

}

Lokale Variable int j Parameter int a(3) Parameter int b(3) Rücksprungadresse Return-Wert 7

Lokale Variable m

(17)

Anwendung eines Stacks

Speichern lokaler Variablen

Umgekehrte Polnische Notation

5, 4, +

5,4+,2,5+x

5 Enter 4 + 2 Enter 5 + x

Programmiersprache Forth

Parsen eines Postfix-Ausdruckes

(18)

Stack: Java-Implementierung

Beachte: Jede Klasse in Java ist auch vom Typ Object.

In Java ist die Stack-Klasse in java.util vorimplementiert!

public class Stack {

private Object[] elements;

private int topOfStack;

public Stack() { topOfStack = 0;

elements = new Object[10];

}

public Object pop() { Object value = null;

if(topOfStack > 0) {

value = elements[--topOfStack];

elements[topOfStack+1] = null;

}

return value;

}

public void push(Object o) {

if(topOfStack >= elements.length) {

growStack();

}

elements[topOfStack++] = o;

}

private void growStack() { int len = elements.length;

Object[] e = new Object[2*len];

for(int i=0; i<len; i++) { e[i] = elements[i];

elements[i] = null;

}

elements = e;

}

(19)

Umgang mit einem Stack

public static void main(String[] args) { Object o;

Stack meinStack = new Stack();

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

o = new String("Zeichenkette " + i);

meinStack.push(o);

} // for

while(true) {

Object p = meinStack.pop();

if(p == null) break;

System.out.println(p);

}

Zeichenkette 14 Zeichenkette 13 Zeichenkette 12 Zeichenkette 11 Zeichenkette 10 Zeichenkette 9 Zeichenkette 8 Zeichenkette 7 Zeichenkette 6 Zeichenkette 5 Zeichenkette 4 Zeichenkette 3 Zeichenkette 2 Zeichenkette 1 Zeichenkette 0

Ausgabe

(20)

Umgang mit einem Stack

public static void main(String[] args) { Object o;

Stack meinStack = new Stack();

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

o = new String("Zeichenkette " + i);

meinStack.push(o);

} // for

Object p= meinStack.pop();

while(p!=null) {

System.out.println(p);

p = meinStack.pop();

} }

Zeichenkette 14 Zeichenkette 13 Zeichenkette 12 Zeichenkette 11 Zeichenkette 10 Zeichenkette 9 Zeichenkette 8 Zeichenkette 7 Zeichenkette 6 Zeichenkette 5 Zeichenkette 4 Zeichenkette 3 Zeichenkette 2 Zeichenkette 1 Zeichenkette 0

(21)

Umgang mit einem Stack: Beispiel Pyramide

(22)

Algorithmus

Ein Algorithmus ist eine Handlungsvorschrift, die eindeutig beschreibt, wie ein Problem mit endlich vielen Schritten gelöst

werden kann.

Diese Definition schließt die Berechnung der Fibonacci-Zahlen mittels Rekursion mit ein, auch wenn die Rechenzeiten “etwas”

länger sein können. Daher unterscheiden wir zwischen

“theoretischer” Berechenbarkeit und “faktischer”

Berechenbarkeit.

Hierzu betrachten wir sich die Laufzeit (oder der Speicherbedarf) verändert, wenn die zu bearbeitende Problemgröße

systematische geändert wird.

CPU

Speicher

Netzwerk

(23)

Die Laufzeit wird in einer asymptotischen Notation

beschrieben, die weitgehend von unwesentlichen Details Die Komplexität eines Algorithmus ist eine Abschätzung des

Aufwands seiner Berechnung auf dem Computer Formale Definition der O-Notation:

∈ ↔ ∃ ,

0

∀ ≥

0

∶ ≤ ()

Definition:

Funktion f(n) ist in der Menge O(g(n)), wenn es ein c> 0 und ein n

0

∈N gibt, so dass für alle n ≥ n

0

gilt:

f(n) c* g(n)

(24)

Die Komplexität eines Algorithmus

(25)

Groß-Oh-Notation:

Sie bringt zum Ausdruck, dass eine Funktion f(n)

höchstens so schnell wächst, wie eine andere Funktion g(n). g(n)Ist also die obere Schranke für f(n).

Die O-Notation geht auf den Zahlentheoretiker Edmund Landau (1877-1938) zurück; daher wird das „O“ auch als Landau-Symbol bezeichnet

Die Komplexität eines Algorithmus

(26)

Die Komplexität eines Algorithmus ist eine Abschätzung des Aufwands seiner Berechnung auf dem Computer

Formale Definition der O-Notation:

O(1): konstanter Aufwand: Zugriff auf ein Feldelement, Berechnung eines Ausdrucks

O(log n): logarithmischer Aufwand: allgemeine Suchverfahren

O(n): linearer Aufwand: zeichnen einer Linie über n Pixel, Einfügen eines Elements in einen Array

O(n log n): quasilinearer Aufwand: z.B. sortieren mit Quicksort

O(n

2

): quadratischer Aufwand: sortieren mit BubbleSort

O(n

k

): polynomialer Aufwand: Matrizenmultiplikation O(n

3

)

O(2

n

): exponentieller Aufwand: rekursive Fibonacci-Berechnung, entscheidungsbasierte Spiele

∈ ↔ ∃ ,

0

∀ ≥

0

∶ ≤ ()

(27)

Wachstum für Komplexitätsbereiche

Beispiele:

// O(1)

x = x + 1;

y = a[i];

// O(n)

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

x = x + 1;

}

// O(n

2

)

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

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

x = x+1;

(28)

Lineare Suche

schnellstmöglicher Algorithmus,

falls an die zu durchsuchende Menge keine weiteren Bedingungen geknüpft sind.

falls die zu durchsuchende Menge jedoch geordnet ist, kann ein besserer Algorithmus gefunden werden.

Um die Elemente einer Menge M anordnen zu können,

müssen die Elemente vergleichbar sein, d. h. es ist möglich für a, b ∈ M zu entscheiden, ob gilt:

a < b oder a == b oder a > b

(29)

Sollen Klasseninstanzen vergleichbar sein, so wird üblicherweise die Methode int compareTo in der Klasse implementiert.

Mathematik Java Klasseninstanzen Normaler Wert a < b a.compareTo(b) < 0 -1

a = b a.compareTo(b)==0 ß

a>b a.compareTo(b)>0 +1

Beachten Sie:

falls a.compareTo(b) == 0,

dann sollte auch a.equals(b) == true sein, und umgekehrt.

Suchen

(30)

bessere Suchmethode: Suche 450

Voraussetzung: die zu durchsuchende Menge ist sortiert.

2 4 7 8 22 45 47 99 120 450 550

(31)

bessere Suchmethode: Suche 450

Voraussetzung: die zu durchsuchende Menge ist sortiert.

2 4 7 8 22 45 47 99 120 450

mittlere Element, 45<450

mittlere Element, 120<450

gefunden

(32)

bessere Suchmethode

Feld der Größe n mit Ganzzahlwerten:

Wie viele Vergleiche sind nötig bis ein Element x gefunden wird?

(33)

Binäre Suchmethode

Verbale Beschreibung der Binärsuche:

Suche in einem sortierten Datenbestand den Wert der in der Mitte liegt und vergleiche ihn mit dem gesuchten Wert.

Ist der gesuchte Wert kleiner, so wiederhole den Vorgang nur mit der linken Hälfte,

ist der gesuchte Wert größer, so wiederhole den Vorgang nur mit der rechten Hälfte.

Wiederhole den Vorgang, bis das gesuchte Element gefunden

(34)

Binäre Suchmethode

deutlich verbesserter Suchalgorithmus

basiert auf dem Teile und Herrsche Prinzip (“Mantra der Informatik”)

die Laufzeit der binären Suche ist O(log n).

Teile-und-Herrsche wird in der Informatik häufig benutzt:

Betrachte ein Gesamtproblem und teile es in zwei (meist etwa gleich große) Teile.

Löse die Teilprobleme (oft durch ähnliches Vorgehen)

Berechne aus den Teillösungen die Gesamtlösung des

Problems.

(35)

Binäre Suche im Ganzzahl-Array

int binarySearch ( int[] array, int key ) { int u = 0; // untere Grenze

int o = array.length -1; // obere Grenze while( u <= o ) {

int m = (u + o ) / 2; // lese den Wert des mittleren Index if ( array[m] == key ) { // bester Fall

return m;

} else if ( array[m] > key ) {

o = m-1; // Wert in linker Haelfte oder nicht vorhanden } else {

u = m+1; // Wert in rechter Haelfte oder nicht vorhanden } // if

} // while

(36)

Sortier-Verfahren

Anwendungen:

Suchen in großen Datensätzen ist viel effizienter, wenn es sortiert ist (vgl. binäre vs. lineare Suche)

Aber Suche nach Kundennummer, Nachname ???

Finden doppelter Werte

Effizientes Einfügen neuer Werte

Nachfolgende Verfahren werden auf einen 1D-Integer-Array

angewendet. Andere Datenstrukturen sind jedoch möglich.

(37)

Sortier-Verfahren

Bubble Sort

Selection Sort (hier nicht besprochen)

Insertion Sort (hier nicht besprochen)

Quicksort

Eingabe für das Sortierverfahren:

ein Feld hat beliebig angeordnete Datensätze

Ziel:

Sortiere die Datensätze aufsteigend, so dass gilt

E[i] < E[i+1] für alle i.

prog1

(38)

Bubble-Sort

Sei n Anzahl der Elemente Wiederhole:

setze vertauscht auf falsch

Für alle noch nicht sortierten Elemente 0 ... n-1 Vergleiche E[i] mit E[i+1].

Falls E[i] > E[i+1], dann vertausche die Elemente setze vertauscht auf wahr n = n - 1

solange vertauscht und n > 1

Laufzeit: O(n

2

)

(39)

Bubble-Sort

public void bubbleSort( int[] array ) { boolean swapped = true;

while(swapped) { swapped = false;

for(int i=0; i< array.length; i++) { if(array[i] > array[i+1]) {

int temp = array[i];

array[i] = array[i+1];

array[i+1] = temp;

swapped = true;

} //if

} // for

(40)

public void bubbleSort(int[] array) { boolean swapped = true;

int n = array.length;

while(swapped) { swapped = false;

n--;

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

if(array[i] > array[i+1]) { int temp = array[i];

array[i] = array[i+1];

array[i+1] = temp;

swapped = true;

} // if } // for } // while

Bubble-Sort

(41)

Quick-Sort

meist O(n log n), im schlechtesten Fall jedoch O(n

2

) Idee:

Wähle ein Referenzelement aus der Folge (das Element in der Mitte)

Zerlege Folge in zwei Teilfolgen, wobei alle Elemente der einen Folge kleiner als das Referenzelement sind, alle Elemente der anderen Folge sind größer als das Referenzelement.

Wiederhole den Vorgang mit den Teilfolgen solange bis die Länge

einer Teilfolge 0 oder 1 beträgt (diese sind dann trivialerweise

(42)

Algorithmus: Zerteilen in Teilfolgen durch Vertauschen

o: obere Grenze u: untere Grenze

p: Referenzelement bei (o+u)/2

l: linkes äußeres Element das größer oder gleich p ist r: rechtes äußeres Element das kleiner oder gleich p ist Zerteilen:

Es wird ein Teil des Arrays mit o und u bestimmt.

Bestimme das Referenzelement (beliebiger Wert aus der

Folge, meist (o+u)/2)

(43)

Tauschen:

solange(u < o)

l suchen (von links nach rechts nach erstem Element größer order gleich p suchen.

r suchen (von rechts nach links nach erstem Element kleiner oder gleich p suchen.

falls r größer als l: vertausche die Elemente E[l] und E[r]

Im abgearbeiteten Bereich sind links vom Referenzelement nur Elemente, die kleiner als dieses sind, rechts vom Referenzelement nur Elemente, die größer sind.

Diese Teilfolgen sind noch nicht sortiert, daher rekursiver Aufruf für jede der beiden Teilfolgen:

für die linke Teilfolge: falls u < r, teile linke Seite erneut

(44)

Methode teile(u, o) l = u

r = o

p = daten[(u+o)/2]

wiederhole solange l <= r

solange daten[l] <= p und l < o l = l + 1

solange daten[r] >= p und r > u r = r - 1

falls l < r, dann

vertausche daten[l] mit daten[r]

l = l + 1 r = r - 1

Methode quicksort(u, o) m = teile(u, o)

falls u < m-1

quicksort(u, m-1) falls m < o

quicksort(m, o)

(45)

Stufe 1 Stufe 1 Stufe 1 Stufe 1

• Wähle ein Pivotelement p

• erste, letzte, mittlere, random

• Tausche die Elemente in eine

• linke Liste, a(i) <= p

• rechte Liste, a(i) > p

• Stufe 2

• Wähle ein Pivotelement p pro Liste

• erste, letzte, mittlere, random

• Tausche die Elemente in eine

• linke Liste, a(i) <= p

• rechte Liste, a(i) > p

Quick-Sort: Pseudocode

(46)

funktion funktion funktion

funktion quicksort(links, rechts) falls

falls falls

falls links < rechts dann ann ann ann

teiler := teile teile teile teile(links, rechts) quicksort(links, teiler-1) quicksort(teiler+1, rechts) ende

ende ende ende ende ende ende ende

Quick-Sort: Pseudocode

(47)

Quick-Sort: Beispiel

1 13 5 27 7 14 3 8 2

Pivotelement

Index i startet am Anfang der Liste

i++, bis a[i]>p

1 13 5 27 7 14 3 8 2

Index i Index j

(48)

1 13 5 27 7 14 3 8 2

13 >7 2<=7

1 2 5 27 7 14 3 8 13

1 2 5 3 7 14 27 8 13

Weiter mit Rekursion

(49)

1 2 5 3 7 14 27 8 13 Pivotelemente

1 2 3 5 7 13 27 8 14

13 8 27 14

1 2 3 5 7

(50)

void quickSort(int[] arr, int left, int right) { int i = left, j = right;

int tmp;

int pivot = arr[ (left + right) / 2 ];

while (i <= j) {

while (arr[i] < pivot) i++;

while (arr[j] > pivot) j--;

if (i <= j) {

tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;

i++;

j--;

} };

if (left < j)

quickSort(arr, left, j);

if (i < right)

quickSort(arr, i, right);

(51)

Sortierung mit BubbleSort und QuickSort

BubbleSort BubbleSort QuickSort QuickSort

n Zeit ns Zeit ms Zeit ns Zeit ms

100 145516 0 42518 0

200 583164 0 71108 0

300 266108 0 108862 0

400 483832 0 41786 0

500 775230 0 39220 0

600 1142503 0 46550 0

700 1532500 0 55347 0

800 2025495 15 64877 0

900 2570172 0 73674 0

1000 3247537 0 79906 0

2000 13133829 16 178871 0

3000 29703228 31 257677 0

4000 52558773 47 373870 0

5000 81858074 78 475768 0

6000 115988361 125 549442 0

7000 156244983 156 657571 0

8000 198897304 202 760569 0

(52)

• Bubblesort O(n²)

• Heapsort O(n*log(n))

• Merge Insertion O(n*log(n))

• Mergesort O(n*log(n))

• Quicksort O(n*log(n))

• Selectionsort O(n*log(n))

• Shellsort O(n*log(n))

Weitere Sortierverfahren

(53)

Unsortierte Datensätze

Mergesort

Teil1 Teil2 Teil3

Teil1,

sortiert Teil2,

sortiert Teil3,

sortiert

Referenzen

ÄHNLICHE DOKUMENTE

– Semantische Elemente (header, section, summary, details, etc.). – Neue Formulare (number, range,

Beim Anklicken soll der Text der Eingabe ausgegeben werden. Falls leer, .Equals, soll eine Meldung erscheinen

■ Show(Text, Caption, MessageBoxButtons, MessageBoxIcon, MessageBoxDefaultButton, MessageBoxOptions,

Excel durch das Binary Interchange FileFormat (BIFF). • Das BIFF ist ein Format, welches Excel als

Aufrufprogramm erstellen: gemeinsamer Ordner Projektname: testdll.. DLL Projekt erstellen:

■ Xubuntu - mit dem schlanken Xfce als grafischer Oberfläche - besonders für ältere Rechner geeignet. ■ Edubuntu - eine speziell angepasste Version für Schulen, mehr im

•ReiserFS ist ein B*-tree basierendes Dateisystem mit einer guten Leistung und überholt sowohl ext2 und ext3 im Umgang mit kleinen Dateien (kleiner als 4 KB) oftmals mit einem

ESC ddp Übernimmt eine Textzeile in den Standardpuffer und löscht diese und fügt diese nach der nächsten Zeile wieder ein. ESC p Wenn der Standardpuffer eine Zeile enthält, wird