• Keine Ergebnisse gefunden

Lineare dynamische Datenstrukturen

N/A
N/A
Protected

Academic year: 2022

Aktie "Lineare dynamische Datenstrukturen"

Copied!
14
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

.

.

Lineare dynamische Datenstrukturen

Steffen Reith

reith@informatik.fh-wiesbaden.de

Fachhochschule Wiesbaden

21. Mai 2007

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 1 / 28

.

Einleitung

Bis jetzt: Untersuchung von (einigen) Algorithmen und deren Analyse

Dazu wurden nur Variablen und Arrays von fester Gr¨oße benutzt Vorteil: Einfache Handhabung und Deklaration

Nachteile: Unflexibel, da eine feste Grenze existiert und evtl. sehr viel Speicher unn ¨otig verbraucht wird

Um diese Nachteile zu beseitigen ben ¨otigen wir

Datenstrukturen, die

dynamisch wachsen

(und) schrumpfen k ¨onnen.

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 2 / 28

(2)

.

.

Datenstrukturen und Wiederverwertbarkeit

Ziel: Unsere Programme sollen wiederverwertbar sein (Verbesserung der Softwarequalit ¨at)

Programmierer sollen unsere Datenstrukturen leicht benutzen k ¨onnen

Die Implementierung soll jederzeit ¨anderbar sein (ohne dass der Benutzer diese bemerkt)

Abstraktion von unn ¨otige Details (z.B. Speicherlayout) Dieses Verbergen von Details von Datenstrukturen ist als

Geheimnisprinzip

bekannt (Programming by contract). Solche Datenstrukturen sind auch als abstrakte Datentypen (ADT) bekannt.

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 3 / 28

.

Abstrakte Datentypen

Konkrete Datentypen: Werden direkt aus den Basisdatentypen bzw. C++-Klassen konstruiert (wie schon bekannt).

Abstrakte Datentypen: Bestehen aus einer Spezifikation der Schnittstelle nach außen. Verf ¨ugbare Operationen und deren Semantik wird beschrieben.

Abstrakte Datentypen entsprechen Softwaremodulen (, dem Prinzip des Klassenkonzepts in OO-Sprachen). Folgende Prinzipien kommen zum Einsatz:

Kapselung: Ein ADT darf nur ¨uber seine Schnittstellen benutzt werden

Geheimnisprinzip: Die interne Realisierung eines ADT ist verborgen

Das Geheimnisprinzip kommt schon bei den Basisdatentypen zur Anwendung.

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 4 / 28

(3)

.

.

Die Datenstruktur Stack

Eine einfache Datenstruktur ist der Kellerspeicher (engl. Stack).

Ein Stack ist die Verwirklichung des LIFO-Prinzips (LIFO - Last-In-First-Out-Speicher):

Beim Auslesen eines Elements kann nur auf das zuletzt gespeicherte Element zugegriffen werden

Die n ¨achste Ausleseoperation liefert das vorletzte Element, etc.

Anderer Name f ¨ur Stack: Stapel

Die Schnittstelle eines Stapels besteht aus vier Operationen:

void push(Obj data); (Daten auf den Stack legen) Obj pop(); (Oberstes Element entfernen)

Obj top(); (Oberstes Element auslesen und nicht entfernen ) boolean is empty(); (Test ob Stack leer)

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 5 / 28

.

Ein Beispiel

Gegeben sei ein leerer Stack. Nach push(7); push(12);

push(3); push(17); sieht der Stack wie folgt aus:

7 12 3 17

Und drei pop-Operationen ergeben 17, 3 und 12 (in dieser Reihenfolge). ¨Ubrig bleibt:

7

Mit Feldern k ¨onnen wir sicherlich leicht einen Stapel fester Gr¨oße implementieren. Aber:

Wie machen wir das dynamisch?

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 6 / 28

(4)

.

.

Interne Darstellung der Daten

Wir ben ¨otigen eine Hilfsdatenstruktur:

struct Node *next; // Referenz

daten

Referenz (Zeiger) auf nächstes Objekt next

T data; // Nutzdaten }

in C/C++

struct Node {

Nutz−

Objekte dieses Hilfsdatentyps k ¨onnen leicht mit new erzeugt werden.

Deutet die Referenz next auf kein anderes Node-Objekt, so wird der Wert null verwendet.

In C++ wird der struct evtl. durch eine Klasse incl. Zugriffsmethoden implementiert.

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 7 / 28

.

Ablauf der Push-Operation

3 12 7

NULL

head

ptr

17 Schritt 1

ptr head Schritt 2

17 3 12 7

NULL

5

17 3 12 7

NULL

head 5

ptr Schritt 3

17 3 12 7

NULL 5

head Schritt 4

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 8 / 28

(5)

.

.

Einige Hinweise zur C++-Implementierung

template <class T> class Stack {

private:

// Node<T> ist eigene Klasse (noch implementieren) Node<T> *head; // Zeiger auf top-Objekt

unsigned long numElements; // Anzahl der Elemente public:

Stack(); // Konstruktor

∼Stack(); // Destruktor

void push(T &elem);// ’elem’ auf Stack ablegen T pop();// ein Element vom Stack holen

bool isEmpty(); // Test ob Stack leer ist };

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 9 / 28

.

Generische Datentypen

Die Programmlogik eines int-Stacks unterscheidet sich nicht von der Programmlogik eines Stacks von Kundendatens¨atzen.

Ziel: Die Implementierung sollte unabh ¨angig vom Nutzdatentyp sein.

Dazu dienen in C so genannte

”templates“ (vgl. List<Integer>

myIntList). In JAVA verwendet man

”Generics“.

Solche parametrierbare abstrakte Datentypen sind als

”generische Datentypen“ bekannt.

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 10 / 28

(6)

.

.

Laufzeiten & Anwendungen

F ¨ur die Zeitkomplexit ¨at von Operationen auf einen Stapel ergibt sich:

Operation Zeitkomplexit ¨at is empty O(1)

top O(1) push O(1) pop O(1)

Grund: F ¨ur jede Operation sind nur endlich viele elementare Anweisungen auszuf ¨uhren.

Anwendungen von Stapelspeichern:

Speicherung lokaler Variablen von Unterprogrammen Speichern von R ¨ucksprungadressen

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 11 / 28

.

Warteschlangen

Eine Warteschlange (engl. Queue) ist die Verwirklichung des FIFO-Prinzips (FIFO - First In First Out)

Neue Elemente werden hinten an die Schlange angef ¨ugt Alte Elemente werden vorne aus der Warteschlange entfernt

Die Schnittstelle einer Warteschlange besteht aus den Operationen:

append(Obj data); (H ¨ange ein Element hinten an) Obj get(); (Entferne ein Element am Ende)

boolean is empty(); (Test ob Queue leer)

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 12 / 28

(7)

.

.

Ein Beispiel

Gegeben sei eine leere Warteschlange. Nach append(7);

append(12); append(3); append(17); erhalten wir:

head

12 3 17

7

tail

Und dreimal get ergibt dann 7, 12 und 3. Zur ¨uck bleibt die Warteschlange:

17

head tail

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 13 / 28

.

Ablauf der Append-Operation (I)

Schritt 1

head ptr

tail

NULL

7 12 3

17

7 12 3

head

tail

NULL

ptr Schritt 2

NULL

ptr NULL

17 Schritt 3

3 7

head

tail

12

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 14 / 28

(8)

.

.

Ablauf der Append-Operation (II)

7 12

head

tail

NULL

ptr

17 3

Schritt 4

tail

7 12 3

head NULL

17 Schritt 5

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 15 / 28

.

Ablauf der Get-Operation

Die Referenz head kopieren

Dann die im Node enthaltenen Informationen kopieren

Die Referenz head auf den Nachfolger des head-Knotens setzen Uberfl ¨ussiges Element mit¨ delete freigeben (in JAVA unn ¨otig) Die Verkettungsrichtung ist wichtig!

Neue Elemente werden am

”Schwanz“ eingekettet Alte Elemente werden am

”Kopf“ ausgekettet Annahme: Verkettungsrichtung w ¨are umgekehrt

append ist einfach (Schwanz neu setzen)

getw ¨are schwierig, da keine Referenz auf das Vorg ¨angerelement existiert (⇒ komplette Queue durchlaufen)

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 16 / 28

(9)

.

.

Laufzeiten & Anwendungen

F ¨ur die Zeitkomplexit ¨at von Operationen einer Warteschlange ergibt sich:

Operation Zeitkomplexit ¨at append O(1)

get O(1) is empty O(1)

Grund: F ¨ur jede Operation sind nur endlich viele elementare Anweisungen auszuf ¨uhren.

Anwendungen von Warteschlangen:

Warteschlangen von Prozessen in Betriebssystemen (vgl. kfifo.c im Linux Kern)

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 17 / 28

.

Lineare Listen

Bis jetzt: Einf ¨ugen und Entfernen von Elementen nur am Anfang oder Ende der Datenstruktur.

Ziel: Daten sollen geordnet (also sortiert) verwaltet werden und die Datenstruktur soll wieder dynamisch sein

(⇒ Ein- und Ausf ¨ugen an beliebigen Stellen der Datenstruktur) Die Schnittstelle einer linearen Liste besteht aus den Operationen:

insert(Obj data); (Element an der richtigen Stelle einf ¨ugen) Obj remove(Obj data); (Entferne das Element)

boolean is empty(); (Test ob Liste leer)

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 18 / 28

(10)

.

.

Die Remove-Operation

Angenommen wir haben die folgende sortierte Liste gegeben:

NULL

3 7 12 17

head

Es soll remove(12) simuliert werden:

.

.

.

1 Setze

”Vorg ¨anger“ auf head.

.

.

.

2 R ¨ucke den

”Vorg ¨anger“ so lange vor, bis er auf ein Objekt deutet, dessen next-Referenz auf das Objekt deutet, das die zu

entfernenden Daten enth ¨alt.

.

.

.

3 Sichere die Referenz auf den direkten Nachfolger des

”Vorg ¨angerobjekts“ in die tempor ¨are Referenz tmpRef.

.

.

.

4 Setze die next-Referenz des

”Vorg ¨angersobjekts“ auf die next-Referenz von tmpRef.

.

.

.

5 L ¨osche das durch tmpPtr referenzierte Objekt mit delete (in JAVA nicht notwendig).

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 19 / 28

.

Ablauf der Remove-Operation (I)

3 7 12

vorgnger

17

NULL head

Schritt 1

3 7 12

head

vorgnger

NULL 17

Schritt 2

12 7

3

vorgnger Schritt 3

head

tmp

17

NULL

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 20 / 28

(11)

.

.

Ablauf der Remove-Operation (II)

3

Schritt 4

head

tmp

17

NULL

7 12

NULL

3 7

Schritt 5

head

17

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 21 / 28

.

Die Insert-Operation

Es soll insert(9) simuliert werden:

.

.

.

1 Neuen Node erzeugen (mit new) und Daten in diesem speichern.

.

.

.

2 ”Vorg ¨anger“ auf den Anfang der Liste setzen.

.

.

.

3 ”Vorg ¨anger“ solange vorr ¨ucken, bis er auf das Objekt deutet, nach dem das neue Objekt einsortiert werden soll.

.

.

.

4 next-Referenz von tmpRef auf den Nachfolger des Vorg ¨angerobjekts zeigen lassen.

.

.

.

5 next-Referenz des Vorg ¨angerobjekts auf das im ersten Schritt erzeugte Objekt deuten lassen vorgaenger.next = tmpRef;.

Wir erhalten:

NULL

3 7 9 17

head

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 22 / 28

(12)

.

.

Ablauf der Insert-Operation (I)

3 17

NULL

Schritt 1

head

tmpRef

7 9

vorgaenger

3 7 9

head

Schritt 2

17

NULL tmpRef

tmpRef NULL 17

3 head

Schritt 3

7 9

vorgaenger

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 23 / 28

.

Ablauf der Insert-Operation (II)

vorgaenger

9 3

Schritt 4

head

tmpRef

NULL 17

7

3 7

9 head

Schritt 5

17

NULL

tmpRef

vorgaenger

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 24 / 28

(13)

.

.

Einige Bemerkungen

Die oben beschriebenen Operationen funktionieren nur auf dem

”inneren“ Teil der Liste.

Sind Kopf oder Schwanz betroffen, so m ¨ussen diese als Sonderf ¨alle ber ¨ucksichtigt werden. (⇒ fehleranf ¨allig & arbeitsintensiv)

Idee: F ¨uge ein

”kleinstes“ und ein

”gr ¨oßtes“ Dummyelement ein (mit ung ¨ultigen Daten).

NULL head

3 7 12 17

−1 9999

gültiger Datenbereich 1 .. 1000

Sentinel

Diese Dummyelemente nennt man auch Sentinels. (engl. W ¨achter)

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 25 / 28

.

Laufzeiten

F ¨ur die Zeitkomplexit ¨at der Operationen auf Listen mit n Elementen ergibt sich:

Operation Zeitkomplexit ¨at insert O(n)

remove O(n) is empty O(1)

Anwendungen von Listen:

Verwaltung von sortierten Dateien

Implementierungsgrundlage f ¨ur Stacks und Queues

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 26 / 28

(14)

.

.

Weitere lineare Datenstrukturen

Man kann eine lineare Liste auch in eine Ringliste umwandeln:

head

3 7 12 17

Anwendungen:

Zuteilung von Zeitscheiben in einem Betriebssystem

Sende- und Empfangsbuffer bei der Datenkommunikation

Nachteil linearer Listen: man kann sich nur in eine Richtung bewegen L ¨osung: Verkettungen in zwei Richtungen

NULL head

NULL

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 27 / 28

.

Mischen von statischen und dynamischen Ans ¨atzen

Aufgabe: Speichere und verwalte große Datens¨atze (z.B. vollst ¨andige Personaldatens ¨atze)

L ¨osung 1: Arbeiten mit (dynamischen) Arrays:

Vorteil: schneller Zugriff auf die einzelnen Komponenten

Nachteil: z.B. sind Sortieroperationen sehr aufw¨andig (kopieren) L ¨osung 2: Mischansatz:

Den eigentlichen Datensatz in einem dynamisch erzeugten Objekt ablegen

Einen Schl ¨ussel (z.B. Personalnummer) mit einer Referenz auf das Objekt in einem Array ablegen.

Vorteil: Schnelle Zugriffe auf die Daten und effizientes Sortieren Nachteil: Kompliziertere Implementierung

Steffen Reith Lineare dynamische Datenstrukturen 21. Mai 2007 28 / 28

Referenzen

ÄHNLICHE DOKUMENTE

 Gestaltung der Tracking Layer, dazu zählen unter anderem die An- gabe des Zeitfensters, in dem Daten während der Animation gezeigt werden sollen (z.B. die letzten 5

 nicht ganz so tragisch, da Speicher zu Programmende durch Betriebssystem wieder freigegeben wird. •

Idee : Alle Wege ausprobieren Kann sehr groß werden :-(.. Aufgrund des wissenschaftlich fundierten Einsatzes. von Bürgerinitiativen können wir an B =L by..

, Die zu vergleichenden Positionen können mit Hilfe eines Zählen.

färbe uj , mit der anderen Farbe ; / * farbe [ j ' Iz 3- farbig 3*1 überprüfe alle direkten Nachbarn von nj ;. if ( Kollision beim Färben aufgetreten ) then return

Die (n × n)-Dynamikmatrix A des linearen, zeitinvarianten Systems (3.2) kann mit einer regul¨aren (eventuell auch komplexwertigen) Zustandstransformation (3.1) genau dann

Passen Programm und Spezifikation nicht zusammen stellt sich die Frage: Ist das Programm oder die Spezifikation

Rekursive Berechnung der C[i][j] würde zu Berechnung immer wieder derselben Werte führen.