Grundlagen der Algorithmen und Datenstrukturen
Kapitel 3.3-3.5
Prof. Dr. Christian Scheideler
Sequenzen
Sequenz: s = <e0,…,en-1>
Arten, auf Element zuzugreifen:• Feldrepräsentation: absoluter Zugriff über s[i]
• Listenrepräsentation: relativer Zugriff über Nachfolger und/oder Vorgänger
s[0]: e0 s[1] s[2] s[3] s[4] s[5] ….
e0 e1
Nachf.
Vorg.e2
Nachf.
Vorg.e3
Nachf.
Vorg.
Nachf.
Vorg.
….s
Doppelt verkettete Liste
Type Handle=Pointer to Item
Class Item of Element e: Element next: Handle prev: Handle
Class List of Item h: Handle …weitere Variablen und Operationen…
Invariante: (this: Zeiger auf aktuelles Element)next! prev = prev! next = this
ee e
… …
Doppelt verkettete Liste
Einfache Verwaltung:
durch „Dummy“-Element mit Inhalt ?:
Anfangs:
e1?
…e2 en
?
Doppelt verkettete Liste
Zentrale Operation: splice• splice entfernt <a,…,b> aus Sequenz und
fügt sie hinter einem t an.• Bedingung: <a,…,b> muss eine Teilse-
quenz sein, b ist nicht vor a, und t darf nicht in <a,…,b> sein.
Splice (<e1,…,a´,a,…,b,b´,…,t,t‘…,en>, a, b, t) =<e1,…,a´,b´,…,t,a,…,b,t´,…,en>
Doppelt verkettete ListeProcedure splice(a,b,t: Handle) // schneide <a,…,b> heraus a´ := a!prev b´ := b!next a´!next := b´ b´!prev := a´
// füge <a,…,b> hinter t ein t´ := t!next b!next := t´ a!prev := t t!next := a t´!prev := b
……
……
a´ a b b´
……
t a b t´
……
Doppelt verkettete Liste
h: Handle auf ?-Item in List
Function head(): Handlereturn h
Function isEmpty: {0,1}return h.next = h
Function first(): Handlereturn h.next
Function last(): Handlereturn h.prev
e1?
…en
?
Kann evtl. auf ?-Element zeigen!
Kann evtl. auf ?-Element zeigen!
Doppelt verkettete Liste
h: Handle to ?-Item of List
Procedure moveAfter(b,a: Handle)splice(b,b,a) // schiebe b nach a
Procedure moveToFront(b: Handle)moveAfter(b,head()) // schiebe b nach vorne
Procudure moveToBack(b: Handle)moveAfter(b,last()) // schiebe b nach hinten
e1?
…en
Doppelt verkettete Liste
Löschen und Einfügen von Elementen:mittels extra Liste freeList
Procedure remove(b:Handle)moveAfter(b, freeList.head())
Procedure popFront()remove(first())
Procedure popBack()remove(last())
……
h b
…
……
freeList
freeList: gut für Lauf-zeit, da Speicher-allokation teuer
Doppelt verkettete Liste
Function insertAfter(x: Element, a: Handle): HandlecheckFreeLista´ := freeList.first()moveAfter(a´, a)a´!e := xreturn a´
Function insertBefore(x: Element, b: Handle): Handlereturn insertAfter(e, pred(b))
Procedure pushFront(x: Element) insertAfter(x, head())
Procedure pushBack(x: Element) insertAfter(x, last())
……
h a
…
a´x
Doppelt verkettete Liste
Manipulation ganzer Listen:
Procedure concat(L: List) // L darf nicht leer sein!splice(L.first(), L.last(), last())
Procedure makeEmpty()freeList.concat(this)
……
h last
……
L
Doppelt verkettete Liste
Suche nach einem Element:Trick: verwende „Dummy“-Element
Function findNext(x:Element, from: Handle): Handleh.e := xwhile from! e <> x do from := from!nextreturn from
e1x
…en
Einfach verkettete Liste
Type SHandle=Pointer to SItem
Class SItem of Element e: Element next: Handle
Class SList of SItem h: SHandle …weitere Variablen und Operationen…
e…
e e
…
Einfach verkettete Liste
Procedure splice(a´, b, t: SHandle)a´!next := b!nextt!next := a´!nextb!next := t!next
a´ … b b´a
t t´
Stacks und Queues
Grundlegende Datenstrukturen für Sequenzen:
• Stack
• FIFO-Queue:
Stack
Operationen:
• pushBack: <e0,…,en>.pushBack(e) = <e0,…,en,e>
• popBack: <e0,…,en>.popBack = <e0,…,en-1>
• last: last(<e0,…,en>) = en
Implementierungen auf vorherigen Folien.
FIFO-Queue
Operationen:
• pushBack: <e0,…,en>.pushBack(e) = <e0,…,en,e>
• popFront: <e0,…,en>.popFront = <e1,…,en>
• first: first(<e0,…,en>) = e0
Implementierungen auf vorherigen Folien
Beschränkte FIFO-Queue
Class BoundedFIFO(n: IN) of Elementb: Array[0..n] of Elementh=0: IN // Index des ersten Elementst=0: IN // Index des ersten freien Eintrags
Function isEmpty(): {0,1}return h=t
Function first(): Elementreturn b[h]
Function size(): INreturn (t-h+n+1) mod (n+1)
0n 12
3...
h t
b
pop push
Beschränkte FIFO-Queue
Class BoundedFIFO(n: IN) of Elementb: Array[0..n] of Elementh=0: IN // Index des ersten Elementst=0: IN // Index des ersten freien Eintrags
Procedure pushBack(x: Element)assert size<nb[t] := xt := (t+1) mod (n+1)
Procedure popFront()assert (not isEmpty())h := (h+1) mode (n+1)
0n 12
3...
h t
b
pop push
Fazit
• Listen sind sehr flexibel, wenn es darum geht, Elemente in der Mitte einzufügen
• Felder können in konstanter Zeit auf jedes Element zugreifen
• Listen haben kein Reallokationsproblem bei unbeschränkten Größen
! beide Datenstrukturen einfach, aber oft nicht wirklich zufriedenstellend
Beispiel: Sortierte Sequenz
Problem: bewahre nach jeder Einfügung und Löschung eine sortierte Sequenz
1 3 10 14 19
insert(5)
1 3 10 14 195
remove(14)
1 3 10 195
Beispiel: Sortierte Sequenz
S: sortierte Sequenz
Jedes Element e identifiziert über Key(e).
Operationen:
• <e0,…,en>.insert(e) = <e0,…,ei,e,ei+1,…,en>für das i mit Key(ei) < Key(e) < Key(ei+1)
• <e0,…,en>.remove(k) = <e0,…,ei-1,ei+1,…,en> für das i mit Key(ei)=k
• <e0,…,en>.find(k) = ei für das i mit Key(ei)=k
Beispiel: Sortierte Sequenz
• Realisierung als Liste:– insert, remove und find auf Sequenz der
Länge n kosten im worst case (n) Zeit
• Realisierung als Feld:– insert und remove kosten im worst case
(n) Zeit– find kann so realisiert werden, dass es im
worst case nur O(log n) Zeit benötigt(! binäre Suche!)
Beispiel: Sortierte Sequenz
Kann man insert und remove besser mit einem Feld realisieren?
• folge Beispiel der Bibliothek!
• verwende Hashtabellen (Kapitel 4)
Beispiel: Sortierte Sequenz
Bibliotheksprinzip: lass Lücken!
Angewandt auf sortiertes Feld:
1 3 10 14 19
insert(5)
remove(14)
1 3 5 14 1910
1 3 5 1910
Beispiel: Sortierte Sequenz
Durch geschickte Verteilung der Lücken:
amortierte Kosten für insert und remove (log2 n)
1 3 10 14 19
insert(5)
remove(14)
1 3 5 14 1910
1 3 5 1910
Nächste Woche
• Weiter mit Kapitel 4: Hashtabellen
• Midterm am 29. Mai!
• Anmeldung über Grundstudiumstool
Top Related