Informatik I 2. Kapitel. Elementare Datenstrukturen. Datenstrukturen. Datenstrukturen. Rainer Schrader. 28. Mai 2008

Informatik I 2. Kapitel Elementare Datenstrukturen Rainer Schrader Zentrum für Angewandte Informatik Köln 28. Mai 2008 1/1 2/1 Datenstrukturen D...
Author: Johannes Braun
0 downloads 0 Views 463KB Size
Informatik I 2. Kapitel

Elementare Datenstrukturen Rainer Schrader Zentrum für Angewandte Informatik Köln

28. Mai 2008

1/1

2/1

Datenstrukturen

Datenstrukturen • bisher haben wir nur Arrays verwendet, • effiziente Algorithmen brauchen geeignete Datenstruktur

Gliederung

• Einführung • abstrakte Datentypen

• Beispiel: Suche im Telefonbuch • gegeben: Name • gesucht: Telefonnummer

• Listen • Stacks und queues • Anwendungsbeispiele • Bäume



; einfach

• gegeben: Telefonnummer • gesucht: Name •

3/1

; praktisch unmöglich

4/1

Datenstrukturen

Datenstrukturen • offensichtlich ist das Problem in der Zeit Θ(n) lösbar, • aber es geht besser, wenn man viele Anfragen zu einem festen M hat

Nichttriviales Beispiel: Posamp-Problem

• gegeben:

Informelle Beschreibung einer geeigneten Datenstruktur

• n Orte (Postämter) M = {p1 , p2 , . . . , pn } • ihre kartesischen Koordinaten pi = (xi , yi )

• sei VR(pj ) die Menge aller Punkte der Ebene, die näher an pj als an

• zusätzlicher Ort p0 = (x0 , y0 )

• also

jedem anderen Punkt in M liegen, n o VR(pj ) = q ∈ R2 | d (q, pj ) ≤ d (q, pi ) ∀i ∈ {1, 2, . . . n} .

• gesucht: • das zu p0 nächstgelegene Postamt pk , d.h. • d (p0 , pk ) ≤ d (p0 , pi ) für alle i ∈ {1, . . . , n} mit p • d (pi , pj ) = (xi − xj )2 + (yi − yj )2 (Euklidische Distanz)

• VR(pj ) ist die Voronoi-Region von pj • das Voronoi-Diagramm ist die Menge VD(M ) = {VR(pj ) | j ∈ {1, 2, . . . , n}}

5/1

6/1

Datenstrukturen

Datenstrukturen

Beispiel: Idee eines effizienten Verfahrens für eine beliebige Anfrage

• (AD) Aufbau der Datenstruktur: bestimme das Voronoi-Diagramm VD(M ).

• (BA) Beantwortung einer Anfrage: für eine Anfrage p0 : bestimme VR(pk ) mit p0 ∈ VR(pk ). man kann zeigen: (evtl. Kapitel 10)

• (AD) benötigt O(n log n) Zeit. • (BA) benötigt O(log n) Zeit.

7/1

8/1

Datenstrukturen

Datenstrukturen

• Datenstrukturen sollen Operationen auf Objekten unterstützen • evtl. verschiedene Datenstrukturen für verschiedene Operationen

Gliederung

• Einführung • abstrakte Datentypen

• evtl. Verknüpfung von Objekten und Operationen (Klassen)

• Listen • Stacks und queues • Anwendungsbeispiele • Bäume

Abstrakter Datentyp (ADT) besteht aus

• einer oder mehreren Mengen von Objekten • und darauf definierten Operationen

10 / 1

9/1

Datenstrukturen

Datenstrukturen

Beispiel Postamtproblem :

Beispiel: Formulierung eines Algorithmus mit Hilfe von ADT

• Objekte:

Aufgabe:

• endliche Mengen M von Punkten in der Ebene

• gegeben eine endliche Menge M von Punkten in der Ebene • finde ein Paar p0 , q0 von Punkten mit minimalem Abstand d (p0 , q0 )

• ein Punkt p0 in der Ebene

• Operation

ADT:

• „nächster Nachbar“: ordne dem Punkt p0 einen nächstgelegen Punkt aus M zu

• Objekt: endliche Punktmenge M • Operationen:

• Mögliche zusätzliche Operationen: • füge einen Punkt zu M hinzu

• nächster Nachbar • Distanz zweier Punkte

• entferne einen Punkt aus M

• Kardinalität von M • M := M r {p}

Wir haben jedesmal einen anderen ADT.

11 / 1

12 / 1

Datenstrukturen

Datenstrukturen

Algorithmus nearest_neighbours(M) liefert p0 , q0 ∈ M mit minimaler Distanz d (p0 , q0 ) falls M = ∅ oder |M | = 1, so sind p0 und q0 nicht definiert Implementierung (Realisierung als Computerprogramm)

falls |M | ≥ 2:

• wähle zwei Punkte p0 , q0 ∈ M • berechne die Distanz dist := d (p0 , q0 )

• Auswahl von Datenstrukturen für die Objektmengen • Auswahl von Algorithmen für die Operationen

• for all p ∈ M do • bestimme einen nächsten Nachbarn q ∈ M r {p} • berechne die Distanz d (p, q) • falls d (p, q) < dist, so setze: • p0 := p; q0 := q; dist := d (p, q).

• end do 14 / 1

13 / 1

Datenstrukturen

Datenstrukturen Lineare Liste

• Objekte:

Gliederung

• Menge aller endlichen Folgen eines gegebenen Grundtyps • die Schreibweise für eine lineare Liste ist

• Einführung • abstrakte Datentypen

L = ha1 , a2 , . . . , an i,

• Listen • Stacks und queues • Anwendungsbeispiele • Bäume

• hierbei ist L = hi die „leere Liste“

• verschiedene Operationen • im Folgenden ist L eine lineare Liste, x vom Grundtyp und p eine Position

15 / 1

16 / 1

Datenstrukturen

Datenstrukturen

Füge_ein(x,p,L) Entferne(p,L)

• falls L = ha1 , a2 , . . . , ap−1 , ap , ap+1 , . . . , an i 6= hi : L → ha1 , a2 , . . . , ap−1 , x , ap , ap+1 , . . . , an i L → hx , a1 , a2 , . . . , an i L → ha1 , a2 , . . . , an , x i

für L 6= hi und 1 ≤ p ≤ n gilt: für 1 < p ≤ n

• aus ha1 , a2 , . . . , ap−1 , ap , ap+1 , . . . an i

für p = 1 wird

für p = n + 1

ha1 , a2 , . . . , ap−1 , ap+1 , . . . an i.

• falls L = hi und p = 1:

hi → hx i

• undefiniert sonst

• undefiniert sonst

18 / 1

17 / 1

Datenstrukturen

Datenstrukturen

Suche(x,L) Verkette(L,L1,L2)

• liefert eine Position p in L = ha1 , a2 , . . . , an i mit ap = x , falls diese existiert,

• liefert für

• sonst 0.

L1 = ha1 , a2 , . . . , an1 i und L2 = hb1 , b2 , . . . , bn2 i die Liste

Zugriff(p,L)

L = ha1 , a2 , . . . , an1 , b1 , b2 , . . . , bn2 i.

• liefert ap in L = ha1 , a2 , . . . , an i, falls 1 ≤ p ≤ n, • sonst undefiniert.

19 / 1

20 / 1

Datenstrukturen

Datenstrukturen

Gliederung

• Einführung • abstrakte Datentypen

Darstellungen linearer Listen

• sequentielle Darstellung

• Listen

• zusammenhängende Speicherung als Feld mit direktem Zugriff

• sequentielle Listen • verkettete Listen

• verkettete Listen

• Stacks und queues • Anwendungsbeispiele

• verteilte Speicherung, durch Zeiger verknüpft

• Bäume

21 / 1

22 / 1

Datenstrukturen

Datenstrukturen Füge_ein(x,p,L)

Sequentielle Listen \\ fügt x als neues Element an Stelle p ein, falls p zulässig, gibt andernfalls Fehlermeldung aus

Eine sequentiell gespeicherte Liste L besteht aus:

• einer (hinreichend großen) Konstanten maxelzahl • einem Feld element[0, . . . , maxelzahl]

if (L.elzahl = L.maxelzahl or p < 1 or p > L.elzahl + 1) print ”Fehler” else for i = L.elzahl down to p do L.element(i+1) = L.element(i) end do L.element(p) = x L.elzahl = L.elzahl+1 end if

• der aktuellen Listengröße elzahl Ist 0 < L.elzahl ≤ L.maxelzahl, so ist in L.element(1), . . . , L.element(elzahl) die aktuelle Liste abgelegt.

23 / 1

24 / 1

Datenstrukturen

Datenstrukturen

Entferne(p,L)

Suche(x,L)

\\ entfernt das p. Element, falls p zulässig, gibt andernfalls Fehlermeldung aus

\\ liefert die höchste Position, an der x in L vorkommt, 0 sonst

if (L.elzahl = 0 or p < 1 or p > L.elzahl) print ”Fehler” else L.elzahl = L.elzahl - 1 for i = p to L.elzahl do L.element(i) = L.element(i+1) end do end if

L.element(0) = x i = L.elzahl while (L.element(i) 6= x) do i = i-1 end while return i

26 / 1

25 / 1

Datenstrukturen

Datenstrukturen

Zugriff(p,L)

Verkette(L,L1,L2)

\\ gibt das p. Element aus, falls p zulässig, gibt andernfalls Fehlermeldung aus

\\ hänge L2 an L1 an, falls L1 ausreichend lang if (L1.elzahl + L2.elzahl > L1.maxelzahl) print ”Fehler” else if (L2.elzahl > 0) then do for i = 1 to L2.elzahl do L1.element(L1.elzahl + i) = L2.element(i) end do end if L1.elzahl = L1.elzahl + L2.elzahl end if

if (p < 1 or p > L.elzahl) print ”Fehler” else return L.element(p) end if

27 / 1

28 / 1

Datenstrukturen

Datenstrukturen

Gliederung

Laufzeiten

• Einführung • abstrakte Datentypen

Sei n die Länge der Liste Operation suche füge_ein entferne Zugriff verkette

Zeit

• Listen

O(n) O(n) O(n) O(1) O(n2 )

• sequentielle Listen • verkettete Listen

• Stacks und queues • Anwendungsbeispiele • Bäume

29 / 1

30 / 1

Datenstrukturen

Datenstrukturen

eine mögliche Implementation von verketteten Listen

eine Liste L = ha1 , a2 , . . . , an i lässt sich wie folgt darstellen:

• eine verkettete Liste wird „kreuz und quer“ im Speicher abgelegt a1

• eine Liste ist gegeben als eine Folge von Knoten • jeder Knoten besteht aus

a2

...

an

DUMMY-Elemente

head

tail

(a) einem Listenelement dat (b) einem Zeiger next auf das nächste Listenelement

• zwei Dummy-Elemente als „Kopf“ und „Schwanz“ der Liste

eine leere Liste sieht dann wie folgt aus:

• einem Zeiger head auf das Kopfelement • einem Zeiger tail auf das Schwanzelement • der Zeiger des Schwanzelements zeigt auf das vorangehende Element

head

31 / 1

tail

32 / 1

Datenstrukturen

Datenstrukturen Füge_ein(x,p,L)

Vereinbarung:

• Zeiger von x := Zeiger von Element p − 1 • Zeiger von Element p − 1 := Zeiger auf x

Die Position p ist gegeben durch einen Zeiger auf den Knoten, dessen Zeiger auf das p.te Listenelement zeigt:

Skizze für Füge_ein: ap

vorher:

ap−1

ap

p

p nachher:

ap−1

ap

Die Listenoperationen lassen sich wie folgt durchführen: x

Wir überprüfen hier nicht, ob p ein legaler Zeiger ist. 33 / 1

34 / 1

Datenstrukturen

Datenstrukturen

Entferne(p,L)

• Zeiger von p − 1 := Zeiger von Element p • (entferne Knoten p)

Suche(x,L) liefert die Position des ersten Listenelements mit dem Schlüssel x , falls es existiert, sonst NULL. Suche(x,L)

Skizze für Entferne(p,L):

vorher:

ap−1

ap

• kopiere x in das Datumsfeld des Schwanzes • beginnend mit dem Kopfelement suche nach x

ap+1

• wird x in einem Element p gefunden: p nachher:

ap−1

• ist p nicht das Schwanzelement: gib Zeiger auf p zurück • andernfalls gib Null zurück

ap+1

Wir überprüfen hier nicht, ob p ein legaler Zeiger ist.

35 / 1

36 / 1

Datenstrukturen

Datenstrukturen Doppelte Verkettung

Verkette(L,L1,L2)

• tail1 zeigt auf das Schwanzelement von L1 • der Zeiger dieses Schwanzelements zeigt auf das letzte Element von L1 • biege dessen Zeiger auf den Zeiger des Kopfelements von L2 um • entferne das Schwanzelement von L1 und das Kopfelement von L2

• manchmal ist es hilfreich, eine Kette auch „rückwärts“ durchlaufen zu können

• wir verwenden einen zusätzlichen Zeiger auf den jeweiligen Vorgänger • hier können wir die Position p durch einen Zeiger auf den Knoten mit dat-Komponente ap definieren

Skizze für Verkette: head1 head

ap−1

...

ap

ap+1

p

tail1

Beispiel für Entferne: tail

... head2

ap−1

ap+1

tail2 37 / 1

38 / 1

Datenstrukturen

Datenstrukturen

Zusammenfassung: Gliederung Operation suche füge_ein entferne Zugriff verkette

sequentiell Θ(n) Θ(n) Θ(n) Θ(1) Θ(n2 )

verkettet Θ(n) Θ(1) Θ(1) Θ(1) Θ(1)

• Einführung • abstrakte Datentypen • Listen • Stacks und queues • Anwendungsbeispiele • Bäume

39 / 1

40 / 1

Datenstrukturen

Datenstrukturen

Stapel

Schlange

• ist eine spezielle Liste • Einfügen und Entfernen nur am Anfang der Liste erlaubt

• ist eine spezielle Liste • Einfügen nur am Ende, Entfernen nur am Anfang der Liste

• „LIFO“: last-in-first-out

• „FIFO“: first-in-first-out

• Operationen:

• Operationen:

• empty(L): teste, ob L leer ist • pop(L,x): setze x := a1 ; entferne a1

• enqueue(L,x): füge x am Ende von L ein • dequeue(L,x): setze x = a1 , entferne a1 aus L • empty(L): teste, ob L leer ist

• top(L,x): setze x := a1 (ohne zu entfernen)

• top(L,x): setze x := a1 (ohne zu entfernen)

• push(L,x): füge x am Anfang von L ein

42 / 1

41 / 1

Datenstrukturen

Datenstrukturen

• alle Stapel-, Schlangen- und Doppelschlangen-Operationen können mit konstanter Laufzeit implementieren werden

Doppelschlangen

• sowohl sequentiell als auch verkettet

• beide push- und pop-Operationen sowie • empty(L), top(L,x), bottom(L,x)

• Anwendung als Warteschlangen und Vorrangwarteschlangen • sequentiell implementierte Schlangen sollten „zyklisch“ verwaltet werden

43 / 1

44 / 1

Datenstrukturen

Datenstrukturen

Skizzen für sequentielle Speicherung Stapel

(Doppel−)Schlange

maxn frei

1111 0000 0000 1111 Stapel

1111 0000 0000 1111 0000 1111 0000 1111

1111111111111111111 0000000000000000000 0000000000000000000 1111111111111111111 0000000000000000000 1111111111111111111 Anfang 0000000000000000000 1111111111111111111 0000000000000000000 1111111111111111111 0000000000000000000 1111111111111111111 0000000000000000000 1111111111111111111 0000000000000000000 maxn 1111111111111111111 frei 0000000000000000000 1111111111111111111 0000000000000000000 1111111111111111111 0000000000000000000 0 1111111111111111111 0000000000000000000 1111111111111111111 0000000000000000000 1111111111111111111 00000000000000000001 Ende1111111111111111111 0000000000000000000 1111111111111111111 0000000000000000000 1111111111111111111 0000000000000000000 1111111111111111111 0000000000000000000 1111111111111111111 0000000000000000000 1111111111111111111

Gliederung

• Einführung • abstrakte Datentypen • Listen • Stacks und queues • Anwendungsbeispiele • Bäume

45 / 1

Datenstrukturen

46 / 1

Datenstrukturen

Definition eines wohlgeformten Klammerausdrucks Anwendung eines Stapels: wohlgeformte Klammerausdrücke (1) () ist ein wohlgeformter Klammerausdruck

• Test, ob Klammerfolgen wohlgeformt sind • Beispiel:

(()())

• Beispiel:

((())(

(2) sind w1 und w2 wohlgeformte Klammerausdrücke, so ist auch w1 w2 ein wohlgeformter Klammerausdruck



(3) mit w ist auch (w ) ein wohlgeformter Klammerausdruck



(4) nur die nach (1) bis (3) gebildeten Zeichenketten sind wohlgeformte Klammerausdrücke

47 / 1

48 / 1

Datenstrukturen

Datenstrukturen

Anwendung eines Stapels: Test von Klammerausdrücken

Anwendung von Listen: Datenstruktur für Projektplanungen

• durchsuche Zeichenkette von links nach rechts

gegeben: n Teilprojekte eines Projekts (Bauprojekt, Kfz-Fertigung, …) mit

• Zeitangaben über die Dauer der Teilprojekte • Reihenfolgebedingungen zwischen einzelnen Teilprojekten

• wird „(“ gefunden: lege sie auf Stapel • wird „)“ gefunden:

bestimme:

• ist Stapel leer ; nicht wohlgeformt

• Gesamtdauer • Pufferzeiten

• andernfalls entferne obere Klammer vom Stapel

• am Ende:

• kritische Pfade • …

• ist Stapel nicht leer ; nicht wohlgeformt • andernfalls ; wohlgeformt

49 / 1

50 / 1

Datenstrukturen

Datenstrukturen 12

Beispiel mit 4 Teilprojekten

• TP1 : Dauer: 12 • TP2 : Dauer: 6, muss warten auf Beendigung von TP1 , TP3 • TP3 : Dauer: 9, muss warten auf Beendigung von TP1 • TP4 : Dauer: 7, muss warten auf Beendigung von TP2 , TP3

6 1

2

3

4

9

7

Darstellung mit verketteten Listen 12

6 1

3 9

2

4

1

2

2

4

3

2

4

NIL

3

4

7

51 / 1

52 / 1

Datenstrukturen

Datenstrukturen

gerichteter Graph G = (V , E )

(ungerichteter) Graph G = (V , E )

besteht aus:

besteht aus:

• einer endlichen Menge V von Knoten • einer endlichen Menge E von gerichteten Kanten • jeder Kante e ∈ E entspricht ein Paar u, v von Knoten

• einer endlichen Menge V von Knoten • einer endlichen Menge E von Kanten • jeder Kante e ∈ E entspricht ein Paar u, v von Knoten • u, v sind die Endknoten von e

• u Startknoten, v Endknoten von e • wir identifizieren e und das Knotenpaar, d.h. e = (u, v )

• wir identifizieren e und das Knotenpaar, d.h. e = {u, v }

• Veranschaulichung wie vorher:

• Veranschaulichung:

• Knoten als Kreise

• Knoten als Kreise

• Kanten als „Pfeile“

• Kanten als Verbindungen, Strecken, …

• Darstellung z.B. durch „Adjazenzlisten“

• Darstellung z.B. durch „Adjazenzlisten“

53 / 1

54 / 1

Datenstrukturen 1

2

3

4

Datenstrukturen

Gliederung

• Einführung • abstrakte Datentypen

Darstellung mit verketteten Listen

1

2

3

2

1

3

4

3

1

2

4

4

2

3

• Listen • Stacks und queues • Anwendungsbeispiele • Bäume

55 / 1

56 / 1

Datenstrukturen

Datenstrukturen

Bäume

• wir werden im Laufe der Vorlesung immer wieder auf

bestehen aus:

graphentheoretische Modelle und Fragestellungen stoßen

• einer endlichen Menge V von Knoten • ein Knoten ist als Wurzel ausgezeichnet • jeder Knoten hat eine endliche Menge von direkten

• insbesondere kann die nächste Datenstruktur als gerichteter Graph aufgefasst werden

Nachfolgern (Söhnen)

• sie stellt ebenso eine Verallgemeinerung von Listen dar

• die Wurzel hat keinen direkten Vorgänger (Vater) • jeder andere Knoten hat genau einen direkten Vorgänger

57 / 1

58 / 1

Datenstrukturen

Datenstrukturen

Sprechweisen Bäume (rekursive Definition)

Sei T ein Baum mit Wurzel r und Unterbäumen T1 , . . . , Tk . Ferner sei ri die Wurzel des Baumes Ti .

bestehen aus einer endlichen Menge V von Knoten, so dass gilt:

• es gibt einen ausgezeichneten Knoten r (Wurzel) • die restlichen Knoten sind partitioniert in Teilmengen T1 , . . . , Tk , die

• ri ist i-ter Sohn von r , r ist Vater der r1 , . . . rk , • rj ist Bruder von ri , • u ist Nachfolger von ri , falls u im Unterbaum Ti liegt, • ein Knoten ohne Nachfolger heißt Blatt,

selbst wieder Bäume sind

• r zeigt auf die Wurzeln der Teilbäume r1 , . . . , rk

• Knoten von T , die nicht Blatt sind, heißen innere Knoten,

59 / 1

60 / 1

Datenstrukturen

Datenstrukturen Bezeichnungen

Sprechweisen

T1 5

Sei T ein Baum mit Wurzel r und Unterbäumen T1 , . . . , Tk .

Wurzel

T2

Niveau

2

0

Ferner sei ri die Wurzel des Baumes Ti . 3

7

• eine Folge von Knoten v0 , v1 , . . . , vk heißt Weg, falls vi +1 Nachfolger

linker Unterbaum 5 von

von vi ist für alle 0 ≤ i ≤ k − 1, 2

• der Weg v0 , v1 , . . . , vk hat die Länge k , • Tiefe(v , T ) = Länge des Weges von Knoten v zur Wurzel r , • Höhe(v , T ) = Länge des längsten Weges von v zu einem Blatt, • Höhe(T ) = Höhe (Wurzel, T ).

5

1

3 Knoten

8

Kanten

Tiefe(7)=2

7

5

3 ist Vater von 2 3 ist Vater von 5 2 ist linker Sohn von 3 5 ist rechter Sohn von 3

2

8

3

Blatt 5

4

62 / 1

61 / 1

Datenstrukturen

Datenstrukturen Darstellungen von Bäumen

In der Informatik werden Bäume stets so dargestellt, dass die Wurzel oben und die Blätter unten liegen.

• verkettete Liste mit variabler Zeigerzahl

Wurzel

Daten Anzahl der Söhne

Pointer zu Sohn

Bäume können aufgefasst werden als:

• spezielle gerichtete Graphen, • verallgemeinerte Listen, in denen ein Knoten mehr als einen Nachfolger Nachteil: variable Zeigerzahl

haben kann.

63 / 1

64 / 1

Datenstrukturen

Datenstrukturen

• verkettete Liste mit 3 Datentypen

Beispiel:

• jedes Element der Liste besteht aus 3 Teilen:

0

1

1

Datum

Indikator

1

Zeiger 2

3

6

0

4

4 0

5

1

2

0

3

0

7

7 1

• Indikator = 0: ; Datum ist eine zu speichernde Größe • Indikator = 1: ; Datum ist ein Zeiger auf eine Liste mit Unterbaum

0

5

0

6

• wir betrachten überwiegend Bäume mit spezieller Struktur • etwa durch Beschränkung der Anzahl der Söhne (; einfachere Speicherung). 65 / 1

66 / 1

Datenstrukturen

Datenstrukturen

Binäre Bäume

Lemma

Ein Baum, in dem jeder Knoten höchstens 2 Söhne hat, heißt binär.

Ein binärer Baum der Höhe h hat höchstens 2h+1 − 1 Knoten und 2h Blätter.

Darstellung binärer Bäume Beweis: (per Induktion): √ • h=0:

• durch 2 Felder Leftsoni und Rightsoni • dazu ggf. Informationen über: Inhalt der Knoten, Väter, # Nachfolger in zusätzlichen Feldern 1

2

3

4

5

6

1 2 3 4 5 6

R 4 6 -

• sei T ein Baum der Höhe h • T hat höchstens 2 Söhne r1 und r2 • r1 , r2 sind Wurzeln von Unterbäumen der Höhe höchstens h − 1

L 2 3 5 -

• per Induktion haben T1 und T2 jeweils höchstens • 2h − 1 Knoten und 2h−1 Blätter

• damit hat T höchstens • 2 · (2h − 1) + 1 = 2h+1 − 1 Knoten und 2 · (2h−1 ) = 2h Blätter.

67 / 1

68 / 1

Datenstrukturen

Datenstrukturen • per Induktion gilt:

Satz

mittlere Tiefe(T1 ) ≥ log k1 ,

Die maximale und die mittlere Tiefe eines Blattes in einem Binärbaum mit k Blättern beträgt mindestens log k .

• die Tiefe in T ist um 1 größer als in T1 bzw. T2 • somit:

Beweis:

• haben alle Blätter die Tiefe höchstens t , so hat T höchstens 2t Blätter • ⇒ die maximale Tiefe ist mindestens log k .

” k “ ” k1 “ 2 mittlere Tiefe(T1 ) + 1 + mittlere Tiefe(T2 ) + 1 k k k1 k2 ≥ (log k1 + 1) + (log k2 + 1) k k 1 = (k1 log 2k1 + k2 log 2k2 ) k := f (k1 , k2 )

mittlere Tiefe(T ) =

Beweis des zweiten Teils per Induktion: √ • k =1: .

• sei T ein Baum mit k ≥ 2 Blättern • seien T1 , T2 die Teilbäume unter der Wurzel mit k1 bzw. k2 Blättern • per Induktion gilt: mittlere Tiefe(T1 ) ≥ log k1 ,

mittlere Tiefe(T2 ) ≥ log k2

Die Funktion f (k1 , k2 ) nimmt ihr Minimum unter der Bedingung k1 + k2 = k im Punkt k1 = k2 = k2 an. Somit:

mittlere Tiefe(T2 ) ≥ log k2 mittlere Tiefe(T ) ≥

1 k k k k ( log 2 + log 2 ) = log k . k 2 2 2 2 70 / 1

69 / 1

Datenstrukturen

Datenstrukturen

Definition

Definition

Ein binärer Baum der Höhe h heißt voll, wenn er 2h+1 − 1 Knoten hat.

Ein binärer Baum mit n Knoten heißt vollständig, wenn seine Knoten den ersten n Knoten eines sequentiell dargestellten vollen binären Baumes entsprechen.

Sequentielle Darstellung Die Knoten des vollen binären Baums werden beginnend in der Wurzel auf jedem Tiefenniveau von links nach rechts durchnumeriert.

1

2

3

1

4 2

4

5

6

3

5

6

7

71 / 1

72 / 1

Datenstrukturen

Datenstrukturen

Lemma

Kompakte Darstellung vollständiger binärer Bäume

Für einen vollständigen binären Baum T mit n Knoten gilt

Vollständige binäre Bäume haben eine kompakte sequentielle Darstellung der Relationen Vater, linker Sohn und rechter Sohn (ohne Zeiger):

Höhe(T ) = dlog(n + 1)e − 1.



bi /2c : für i > 1 − : für i = 1 (Wurzel)



2i : für 2i ≤ n − : für 2i > n



2i + 1 : für 2i + 1 ≤ n − : für 2i + 1 > n

Vater (i ) =

Beweis (per Induktion):

• sei h die Höhe von T • die Knotenanzahl von T liegt zwischen denen der vollen Bäume der

Leftson (i ) =

Höhe h und h − 1

• ⇒ 2h − 1 < n ≤ 2h+1 − 1 • ⇒ h < log(n + 1) ≤ h + 1 • ⇒ h < dlog(n + 1)e ≤ h + 1

Rightson (i ) =

(da h ∈ N)

• ⇒ h + 1 = dlog(n + 1)e.

73 / 1

74 / 1

Datenstrukturen

Datenstrukturen



bi /2c : für i > 1 − : für i = 1 (Wurzel)

• diese Numerierung ist eine spezielle Aufzählung der Knoten eines



2i : für 2i ≤ n − : für 2i > n

• in einigen Anwendungen müssen wir die Knoten eines Baumes



2i + 1 : für 2i + 1 ≤ n − : für 2i + 1 > n

Vater (i ) = Leftson (i ) = Rightson (i ) =

Baums systematisch durchsuchen: • zum Ausgeben der Einträge • zum Aufsummieren der Einträge • zur Bildung eines Mittelwerts über die Einträge,. . .

1

• wir wollen somit die Knoten in einer bestimmten Reihenfolge

2

durchlaufen

3

• die gebräuchlichsten Reihenfolgen: 4

5

6

7

• Präordnung • Postordnung • symmetrisches Durchmustern (nur für Binärbäume)

75 / 1

76 / 1

Datenstrukturen

Datenstrukturen

Sei T ein Baum mit Wurzel r und Söhnen r1 , . . . , rk .

Eigenschaften der Durchmusterungen

Präordnung

Wir identifizieren Knoten mit ihrer Nummer.

(1) Durchmustere die Wurzel

Präordnung

(2) Durchmustere in Präordnung nacheinander T1 , . . . , Tk

(1) Durchmustere die Wurzel (2) Durchmustere in Präordnung nacheinander T1 , . . . , Tk

Postordnung

Sei r die Wurzel des Teilbaums Tr . Dann ist

(1) Durchmustere in Postordnung nacheinander T1 , . . . , Tk

v ∈ Tr ⇐⇒ r ≤ v ≤ r + |Tr | − 1.

(2) Durchmustere die Wurzel symmetrisches Durchmustern von Binärbäumen

Folgerung

(1) Durchmustere in symmetrischer Ordnung Tlinks (falls er existiert)

Ist |Tr | bekannt, so kann in O(1) Schritten entschieden werden, ob v Nachfolger von r ist.

(2) Durchmustere die Wurzel (3) Durchmustere in symmetrischer Ordnung Trechts (falls er existiert)

78 / 1

77 / 1

Datenstrukturen

Datenstrukturen

Postordnung

symmetrisches Durchmustern von Binärbäumen

(1) Durchmustere in Postordnung nacheinander T1 , . . . , Tk

(1) Durchmustere in symmetrischer Ordnung Tlinks (falls er existiert)

(2) Durchmustere die Wurzel

(2) Durchmustere die Wurzel (3) Durchmustere in symmetrischer Ordnung Trechts (falls er existiert)

Sei r die Wurzel des Teilbaums Tr . Dann ist v ∈ Tr ⇐⇒ r − |Tr | + 1 ≤ v ≤ r .

Die Knoten im linken Teilbaum von r tragen kleinere Nummern als r , die im rechten größere.

Folgerung

Folgerung

Ist |Tr | bekannt, so kann in O(1) Schritten entschieden werden, ob v Nachfolger von r ist.

Wir können (auch nach dem Löschen von Knoten) in O(Höhe(T )) entscheiden, ob ein Knoten mit der Nummer p vorkommt.

79 / 1

80 / 1

Datenstrukturen

Datenstrukturen Nichtrekursiver Algorithmus zur symmetrischen Durchmusterung begin count = 1 v = root Top = 0 left: while (leftson(v) 6= leer) then push (Stack, v) v = leftson(v) end while Center: Number(v) = count count = count + 1 if (rightson(v) 6= leer) then v = rightson(v) goto left end if if (top 6= 0) then Pop(Stack, v) goto center end if end

Rekursiver Algorithmus zur symmetrischen Durchmusterung

begin count = 1 SymmOrd(Wurzel) end //Hauptprogramm

procedure SymmOrd(v) if (leftson(v) 6= leer) then SymmOrd(leftson(v)) Number(v) = count count = count + 1 if (rightson(v) 6= leer) then SymmOrd(rightson(v)) end

81 / 1

82 / 1

Datenstrukturen

Datenstrukturen Durch Einfügen und Löschen von Stichworten kann der Suchbaum wie folgt aussehen:

Stichwortsuche

• gegeben: ein Lexikon mit n Stichworten • Frage: ist ein gegebener Begriff im Lexikon enthalten?

g a

b

d

Zwei möglich Ansätze:

i

c d

• verkettete Listen: ; O(n) im worst-case

b

f

h

j

• binärer Baum als Suchbaum organisiert: j

a

c

e

• Wörter im linken Unterbaum sind alphabetisch größer als das Wort in der Wurzel Wir werden versuchen, diese Situation zu verhindern, und balancierte Bäume verwenden.

• Wörter im rechten Unterbaum sind alphabetisch kleiner als das Wort in der Wurzel

Wir verschieben daher die Laufzeituntersuchungen der Operationen Folgerung

Füge_ein, Entferne, Suche und Zugriff auf Bäumen auf ein späte-

Wir können in O(Höhe(T )) entscheiden, ob das gesuchte Wort im Lexikon vorkommt.

res Kapitel. 83 / 1

84 / 1