12.04.2011

Werbung
Datenstrukturen und Algorithmen
Einführung
Komplexität von Algorithmen
(Folie 34, Seite 18 im Skript)
Java
Wir verwenden oft Java für Datenstrukturen und Algorithmen.
Die Vorlesung ist aber von der Programmiersprache unabhängig.
Lernziel sind die einzelnen Algorithmen und Datenstrukturen, nicht
ihre Umsetzung in Java.
Für das Verständnis der Vorlesung sind Kenntnisse in einer
objektorientierten Sprache notwendig.
Datenstrukturen und Algorithmen
Einführung
Komplexität von Algorithmen
(Folie 35, Seite 18 im Skript)
Generische Typen
Nur Konzepte aus der Vorlesung Programmierung.
Mit einer Ausnahme.
Java
public class DoublePair {
Double a;
Double b;
public Pair (Double a, Double b) {this.a = a; this.b = b; }
public void setfirst(Double a) {this.a = a; }
public void setsecond(Double b) {this.b = b; }
public Double first() {return a; }
public Double second() {return b; }
public String toString () {return"[" + a + "," + b + "]"; }
}
Datenstrukturen und Algorithmen
Einführung
Komplexität von Algorithmen
(Folie 36, Seite 18 im Skript)
Generische Typen
Nur Konzepte aus der Vorlesung Programmierung.
Ausnahme: Generische Typen!
Java
public class Pair hA, Bi {
protected A a;
protected B b;
public Pair (A a, B b) {this.a = a; this.b = b; }
public void setfirst(A a) {this.a = a; }
public void setsecond(B b) {this.b = b; }
public A first() {return a; }
public B second() {return b; }
public String toString () {return"[" + a + "," + b + "]"; }
}
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
Java
public class Array hDi {
protected D[ ] a;
protected int size;
Java
public void set(int i, D d) {
if(i ≥ size) {
size = i + 1;
realloc();
}
a[i] = d;
}
(Folie 37, Seite 20 im Skript)
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 38, Seite 20 im Skript)
Java
private void realloc() {
if(size ≥ a.length) {
D[ ] b = (D[ ]) new Object[2 ∗ size];
for(int i = 0; i < a.length; i ++) if(a[i] 6= null) b[i] = a[i];
a = b;
}
}
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
Java
public D get(int i) {
if(i ≥ size) return null;
return a[i];
}
Warum eine eigene Array-Klasse?
1
Erweiterbarkeit
2
Typsicherheit
3
Anfertigen von Statistiken
(Folie 39, Seite 20 im Skript)
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
Java
public interface MaphK , Di {
public void insert(K k, D d);
public void delete(K k);
public D find(K k);
public boolean iselement(K k);
public int size();
public boolean isempty ();
public Iterator hK , Di iterator ();
public SimpleIterator hK i simpleiterator ();
public Array hK i array ();
public void print();
}
(Folie 40, Seite 21 im Skript)
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 41, Seite 21 im Skript)
Assoziative Arrays
Java
public abstract class Dictionary hK , Di implements MaphK , Di {
public abstract void insert(K k, D d);
public abstract void delete(K k);
public abstract Iterator hK , Di iterator ();
public D find(K k) {
Iterator hK , Di it;
for(it = iterator (); it.more(); it.step()) {
if (it.key ().equals(k)) {
return it.data();
}
}
return null;
}
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 42, Seite 23 im Skript)
Doppelt verkettete Listen
Zusätzlicher Listenkopf
Daten in Knoten gespeichert
Zeiger zum Vorgänger und Nachfolger
Zyklisch geschlossen
–
–
4
3
Geeignet für kleine assoziative Arrays.
Für Adjazenzlistendarstellung sehr geeignet.
2
1
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 43, Seite 23 im Skript)
Der Konstruktor muß den Listenkopf head erzeugen.
Der Vorgänger und Nachfolger von head ist head selbst.
–
Java
public class ListhK , Di extends Dictionary hK , Di {
ListnodehK , Di head;
public List() {
head = new ListnodehK , Di(null, null);
head.pred = head.succ = head;
}
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 44, Seite 23 im Skript)
Java
class ListnodehK , Di {
K key ;
D data;
ListnodehK , Di pred, succ;
Listnode(K k, D d) {
key = k; data = d; pred = null; succ = null; }
void delete() {
pred.succ = succ; succ.pred = pred; }
void copy (ListnodehK , Di n) {
key = n.key ; data = n.data; }
void append(ListnodehK , Di newnode) {
newnode.succ = succ; newnode.pred = this;
succ.pred = newnode; succ = newnode; }
}
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 45, Seite 23 im Skript)
Java
public void append(K k, D d) {
head.pred.append(new ListnodehK , Di(k, d));
}
Java
public void prepend(K k, D d) {
head.append(new ListnodehK , Di(k, d));
}
Java
public void delete(K k) {
ListnodehK , Di n = findnode(k);
if(n 6= null) n.delete();
}
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 46, Seite 23 im Skript)
Java
public D find(K k) {
ListnodehK , Di n = findnode(k);
if(n ≡ null) return null;
return n.data;
}
Java
protected ListnodehK , Di findnode(K k) {
ListnodehK , Di n;
head.key = k;
for(n = head.succ; !n.key .equals(k); n = n.succ);
head.key = null;
if(n ≡ head) return null;
return n;
}
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 47, Seite 24 im Skript)
Einfach verkettete Listen
Kein Zeiger auf Vorgänger
Einfachere Datenstruktur
Operationen können komplizierter sein
Frage: Wie kann ein Element vor einen gegebenen Knoten
eingefügt werden?
Ersetzen und alten Knoten anfügen!
Vorsicht: Eine gefährliche Technik.
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 48, Seite 25 im Skript)
Listen – Laufzeit
Manche Operation sind schnell, manche langsam. . .
Operation Laufzeit
append()
Θ(1)
delete () ∗
Θ(1)
delete ()
Θ(n)
find ()
Θ(n)
insert ()
Θ(n)
∗ direktes Löschen eines Knotens, nicht über Schlüssel
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 49, Seite 26 im Skript)
Iteratoren
Mittels eines Iterators können wir die Elemente einer Map
aufzählen.
Java
public interface Iterator hK , Di {
public void step();
public boolean more();
public K key ();
public D data();
}
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 50, Seite 26 im Skript)
Iteratoren
Mittels eines Iterators können wir die Elemente einer Map
aufzählen.
Java
Iterator hK , Di it;
for(it = map.iterator (); it.more(); it.step()) {
System.out.println(it.key ());
}
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 51, Seite 26 im Skript)
Java
public class StackhDi {
private ListhObject, Di stack;
private int size;
public Stack() {stack = new ListhObject, Di(); size = 0; }
public boolean isempty () {return size ≡ 0; }
public D pop() {
D x = stack.firstnode().data;
stack.firstnode().delete();
size −−;
return x;
}
public void push(D x) {stack.prepend(null, x); size ++; }
public int size() {return size; }
}
Datenstrukturen und Algorithmen
Einführung
Elementare Datenstrukturen
(Folie 52, Seite 26 im Skript)
Java
public class QueuehDi {
private ListhObject, Di queue;
private int size;
public Queue() {queue = new ListhObject, Di(); size = 0; }
public boolean isempty () {return size ≡ 0; }
public D dequeue() {
D x = queue.lastnode().data;
queue.lastnode().delete();
size −−;
return x;
}
public void enqueue(D x) {queue.prepend(null, x); size ++; }
public int size() {return size; }
}
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
Lineare Suche
Wir suchen x im Array a[0, . . . , n − 1]
Algorithmus
function find1 (int x) boolean :
for i = 0 to n − 1 do
if x = a[i] then return true fi
od;
return false
Die innere Schleife ist langsam.
(Folie 53, Seite 29 im Skript)
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
(Folie 54, Seite 29 im Skript)
Lineare Suche – verbessert
Wir verwenden ein Sentinel-Element am Ende.
Das Element a[n] muß existieren und unbenutzt sein.
Algorithmus
function find2 (int x) boolean :
i := 0;
a[n] := x;
while a[i] 6= x do i := i + 1 od;
return i < n
Die innere Schleife ist sehr schnell.
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
Lineare Suche – ohne zusätzlichen Platz
Algorithmus
function find3 (int x) boolean :
if x = a[n − 1] then return true fi;
temp := a[n − 1];
a[n − 1] := x;
i := 0;
while a[i] 6= x do i := i + 1 od;
a[n − 1] := temp;
return i < n − 1
Erheblicher Zusatzaufwand.
Innere Schleife immer noch sehr schnell.
(Folie 55, Seite 30 im Skript)
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
(Folie 56, Seite 31 im Skript)
Lineare Suche – Analyse
Wieviele Vergleiche benötigt eine erfolgreiche Suche nach x im
Mittel?
Wir nehmen an, daß jedes der n Elemente mit gleicher
Wahrscheinlichkeit gesucht wird.
Es gilt Pr[x = a[i]] = 1/n für i ∈ {0, . . . , n − 1}.
Sei C die Anzahl der Vergleiche:
C = i + 1 gdw. x = a[i]
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
(Folie 57, Seite 31 im Skript)
Lineare Suche – Analyse
Wir suchen den Erwartungswert von C .
Pr[C = i] = 1/n für i = 1, . . . , n
E (C ) =
n
X
k Pr[C = k] =
k=1
Es sind im Mittel (n + 1)/2 Vergleiche.
n
X
k
k=1
n+1
=
n
2
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
Lineare Suche – Analyse
Unser Ergebnis:
Es sind im Mittel (n + 1)/2 Vergleiche.
Ist das Ergebnis richtig?
Wir überprüfen das Ergebnis für kleine n.
n = 1?
n = 2?
(Folie 58, Seite 31 im Skript)
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
Binäre Suche
Wir suchen wieder x in a[0, . . . , n − 1].
Algorithmus
function binsearch(int x) boolean :
l := 0; r := n − 1;
while l ≤ r do
m := b(l + r )/2c;
if a[m] < x then l := m + 1 fi;
if a[m] > x then r := m − 1 fi;
if a[m] = x then return true fi
od;
return false
Wir halbieren den Suchraum in jedem Durchlauf.
(Folie 59, Seite 32 im Skript)
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
Binäre Suche
Java
public boolean binsearch(D d) {
int l = 0, r = size − 1, m, c;
while(l ≤ r ) {
m = (l + r )/2;
c = d.compareTo(get(m));
if(c ≡ 0) return true;
if(c < 0) r = m − 1;
else l = m + 1;
}
return false;
}
(Folie 60, Seite 32 im Skript)
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
(Folie 61, Seite 32 im Skript)
Binäre Suche – Analyse
Java
function binsearch(int x) boolean :
l := 0; r := n − 1;
while l ≤ r do
m := b(l + r )/2c;
if a[m] > x then l := m + 1 fi;
if a[m] < x then r := m − 1 fi;
if a[m] = x then return true fi
od;
return false
Es sei n = r − l + 1 die Größe des aktuellen Unterarrays.
Im nächsten Durchgang ist die Größe m − l oder r − m.
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
Binäre Suche – Analyse
Lemma
Es sei a ∈ R und n ∈ N. Dann gilt
1
ba + nc = bac + n
2
da + ne = dae + n
3
b−ac = −dae
(Folie 62, Seite 33 im Skript)
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
(Folie 63, Seite 33 im Skript)
Binäre Suche – Analyse
Im nächsten Durchlauf ist die Größe des Arrays m − l oder r − m.
Hierbei ist m = b(l + r )/2c.
Die neue Größe ist also
m − l = b(l + r )/2c − l = b(r − l)/2c = b(n − 1)/2c oder
r − m = r − b(l + r )/2c = d(r − l)/2e = d(n − 1)/2e.
Im schlimmsten Fall ist die neue Größe des Arrays
d(n − 1)/2e.
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
(Folie 64, Seite 33 im Skript)
Rekursionsgleichung für binäre Suche
Sei Sn die Anzahl der Schleifendurchläufe im schlimmsten Fall bei
einer erfolglosen Suche.
Wir erhalten die Rekursionsgleichung
(
0
Sn =
1 + Sd(n−1)/2e
falls n < 1,
falls n ≥ 1.
Die ersten Werte sind:
n
Sn
0
0
1
1
2
2
3
2
4
3
5
3
6
3
Wir suchen eine geschlossene Formel für Sn .
7
3
8
4
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
(Folie 65, Seite 33 im Skript)
Lösen der Rekursionsgleichung
Wir betrachten den Spezialfall n = 2k − 1:
l (2k − 1) − 1 m l 2k − 2 m
=
= d2k−1 − 1e = 2k−1 − 1.
2
2
Daher: S2k −1 = 1 + S2k−1 −1 für k ≥ 1
⇒ S2k −1 = k + S20 −1 = k
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
(Folie 66, Seite 34 im Skript)
Binäre Suche – Analyse
n
Sn
0
0
1
1
2
2
3
2
4
3
5
3
6
3
7
3
8
4
Vermutung: S2k = S2k −1 + 1
Sn steigt monoton ⇒ Sn = k, falls 2k−1 ≤ n < 2k .
Oder falls k − 1 ≤ log n < k.
Dann wäre Sn = blog nc + 1.
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
(Folie 67, Seite 34 im Skript)
Binäre Suche – Analyse
Wir vermuten Sn = blog nc + 1 für n ≥ 1.
Induktion über n:
S1 = 1 = blog 1c + 1
n > 1:
Sn = 1 + Sd(n−1)/2e
= 1 + logd(n − 1)/2e + 1.
I.V.
Noch zu zeigen:
blog nc = logd(n − 1)/2e + 1
→ Übungsaufgabe.
Datenstrukturen und Algorithmen
Suchen und Sortieren
Einfache Suche
(Folie 68, Seite 34 im Skript)
Binäre Suche – Analyse
Theorem
Binäre Suche benötigt im schlimmsten Fall genau
blog nc + 1 = log(n) + O(1)
viele Vergleiche.
Die Laufzeit ist O(log n).
Herunterladen