Teil X Grundlegende Datenstrukturen

Werbung
Teil X
Grundlegende Datenstrukturen
Überblick
1
Einführung
2
Datenstrukturen für Kollektionen
3
Queues und Stacks
4
Bäume, Suchbäume und Hash-Tabellen
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
488/543
Datenstrukturen
Immer wiederkehrende Anforderungen an Verwaltung von
Daten im Haupt- und Sekundärspeicher:
typische Anordnungen und Zusammenhänge,
typische Operationen und
immer möglichst effizient!
Vergleichbar Algorithmenmustern für die Verarbeitung von
Daten: „klassische“ Datenstrukturen als Muster für
effiziente Verwaltung von Daten
Darüber hinaus: viele klassische Datenstrukturen oft als
direkt wiederverwendbare Implementierungen in
Programmiersprachenbibliotheken vorhanden
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
489/543
Beispiele für Datenstrukturen und deren
Verwendung
Prüfungslisten mit geordneten Studentendaten
Knoten- und Kantenlisten in BREP-Modellen
Das Inventory einer Computerspielfigur als Menge von
Gegenständen
Verzeichnisbäume zur Verwaltung von Dateien
Straßennetzwerke eines Routenplaners als Graphen
Warteschlangen mit Prozessen für die Prozessverwaltung
des Betriebssystems
Der Programmstack zur Verwaltung lokaler Daten von
Funktionen während der Programmausführung
B-Bäume als Indexe für schnelle Zugriffe in
Datenbanksystemen (→)
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
490/543
Definition: Datenstrukturen
Definition (Datenstruktur)
Eine Datenstruktur ist eine Anordnungsvorschrift zur
Organisation und Speicherung von Daten, die für bestimmte
Klassen von Anwendungen einen effizienten Zugriff ermöglicht.
Umfasst zwei wesentliche Aspekte:
Schnittstelle: Festlegung der möglichen Operationen und des
Verhaltens als abstrakte Spezifikation (Abstrakte
Datentypen →) oder konkrete
Programmierschnittstelle (z.B. Bibliotheken wie
C++ Standard Template Library →)
Implementierung: konkrete Umsetzung in einer
Programmiersprache durch möglichst effiziente
Speicherstrukturen und Algorithmen
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
491/543
Abstrakte Datentypen
Abstrakte Datentypen (ADTs) als
implementierungsunabhängige Spezifikationmethode der
Schnittstelle und der Semantik
Beispiel: Menge
type Set[Item]
operators
create: → Set
is_empty: Set → Bool
insert: Set × Item → Set
is_in: Set × Item → Bool
axioms ∀s : Set, ∀i,j : Item
is_empty (create) = true
is_empty (insert (s, i)) = false
is_in (create, i) = false
is_in (insert (s, i), j) =
if i=j then true else is_in (s, j)
insert(insert(s,i),j) = insert(insert(s,j),i)
insert(insert(s,i),i) = insert(s,i)
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
492/543
Eigenschaften von Datenstrukturen
Datenstrukturen sind ...
... komplex: werden durch Typkonstruktoren (mit Zeigern,
Feldern, Strukturen, Klassen, etc.) aus
einfacheren Strukturen zusammengesetzt und
letztendlich auf Basisdatentypen (numerische,
alphanumerische) zurückgeführt
... dynamisch: können konkrete Ausprägung zur Laufzeit
ändern, um zum Beispiel beliebige Anzahl neuer
Fakten aufzunehmen oder diese aus der Struktur
zu entfernen
... wiederverwendbar: erlauben, wenn einmal definiert, den
Einsatz für zahlreiche verschiedene Anwendungen
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
493/543
Datenstrukturen für Kollektionen
Kollektionen: Oberbegriff für Datenstrukturen, die eine
Sammlung/Anzahl von gleichartigen Objekten verwalten
sollen
Wichtigste: Mengen, Multimengen, Listen
Je nach Anwendung sehr unterschiedliche Anforderungen
Duplikate: können (werte-)gleiche Objekte in der Struktur
auftreten
Ordnung: spielt die Reihenfolge der Elemente in der
Struktur eine Rolle
Positionaler Zugriff: kann der Zugriff über die Position
innerhalb der Struktur erfolgen (vergleichbar Array)
Assoziativer Zugriff: kann der Zugriff über einen anderen
Wert (Schlüssel) erfolgen
Iterativer Zugriff: Durchlaufen aller Elemente in der
Kollektion (z.B. mittels Schleife) für alle Strukturen möglich
Abgrenzung zum Feld (Array) in Programmiersprachen:
Feld ist nicht dynamisch, da feste Anzahl von Elementen
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
494/543
Überblick: Kollektionsdatentypen
Kollektionstyp
Array / Feld
Set / Menge
Bag / Multimenge
List / Liste
Map, Hash Table
Eike Schallehn, FIN/ITI
Dynamisch
nein
ja
ja
ja
ja
Duplikate
ja
nein
ja
ja
ja
Grundlagen der Informatik für Ingenieure
Ordnung
ja
nein
nein
ja
nein
Zugriff
Position
Position
Assoziativ
495/543
Schnittstellen von Kollektionsdatentypen
Zum Teil sehr unterschiedlich nach Implementierung
Grundlegende Funktionen für alle Kollektionstypen
Erzeugen einer (leeren) Kollektion
Suchen eines Elementes
Einfügen eines Elementes
Löschen eines Elementes
Spezielle Funktionen für Listen
Element an einer bestimmten Position zurückgeben
Einfügen eines Elementes am Anfang, am Ende, an einer
bestimmten Position
Löschen eines Elementes am Anfang, am Ende, an einer
bestimmten Position
Sortierung der Liste nach einem bestimmten Kriterium
Spezielle Funktionen für Maps/Hash-Tabellen
Einfügen eines Elementes mit Zugriffsschlüssel
Suchen eines Elementes anhand des Schlüssels
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
496/543
Implementierung von Kollektionen /1
Liste
Knoten1
4
Knoten2
17
Knoten3
21
KnotenN
37
NULL
Grundprinzipien für Mengen, Multimengen, Listen etc.
ähnlich
1
2
Verwendung von Klassen oder Strukturen für
Kollektions-Schnittstelle sowie innere Knoten
Verwendung von Zeigern zum Aufbau der dynamischen
Struktur aus einzelnen Knoten
Einfachste Lösung:
Kollektionsobjekt mit Zeiger auf ersten Knoten
Knoten trägt Wert und Zeiger auf nächsten Knoten
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
497/543
Implementierung von Kollektionen /2
Liste
Knoten1
4
Knoten2
17
Knoten3
21
KnotenN
37
NULL
Zusätzlicher Zeiger auf letztes Element im Listenkopf
Erlaubt Einfügen bzw. Löschen des letzten Elementes mit
O(1) statt O(n), da Liste nicht erst komplett durchlaufen
werden muss
Siehe Beispielimplementierung: einfach verkettete Liste in
C (→) über Strukturen
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
498/543
Implementierung von Kollektionen /3
Liste
NULL
Knoten1
4
Knoten2
17
Knoten3
21
KnotenN
37
NULL
Häufig verwendete Implementierung: doppelt verkettete
Liste (Double Linked List) mit „Rückzeigern“ von jedem
Knoten auf seinen Vorgänger
Erlaubt Durchlaufen und Navigieren in beliebige Richtung
Höherer Speicheraufwand
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
499/543
Implementierung von Kollektionen /4
Zahlreiche Alternativen bei tatsächlichen Implementierung
Große Anzahl von Zeigern oft wenig speichereffizient →
intern Verwendung von verketteten Arrays
Zahlreiche Optimierungen, insbesondere für Suche in Liste
(Skip-Listen)
Interne Implementierung als Baum (→) oder Hash-Tabelle
(→) zur Beschleunigung bestimmter Operationen (zum
Beispiel Einfügen in Mengen mit gleichzeitigem Test, ob
Element schon in der Menge)
...
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
500/543
Wiederverwendbarkeit für verschiedene
Elementtypen
Kollektionen werden mit immer wieder gleicher
Funktionalität für viele verschiedene Anwendungen
benötigt, zum Beispiel
Liste von ganzen Zahlen
Liste von Vertexes in OpenGL
Liste von Studenten (Objekte einer Klasse)
...
Bisher: Elementtyp in Knoten-Struktur/Klasse festgelegt
Keine Wiederverwendbarkeit: muss für jede Anwendung
neu programmiert oder angepasst werden
Mögliche Lösungen: void-Pointer (in C) bzw. Templates
mit Typparametern in C++ (Java, uva.)
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
501/543
Elemente mittels void*
class Node {
private:
void* element;
...
}
Erzeugung einzelner Elemente als separate Objekte auf
dem Heap und Referenzierung über untypisierten (void)
Zeiger
Nachteile:
Nicht typsicher: Kollektion kann Elemente beliebigen Typs
enthalten → fehleranfällig
Erfordert prinzipiell Arbeit mit Zeigern
Einzige Option in vielen älteren Programmiersprachen,
zum Beispiel C
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
502/543
Elemente mittels Templates /1
template <class T>
class Node {
private :
T element;
...
};
template <class T>
class List { ... };
Typparameter in aktuellen Programmiersprachen
(Templates in C++, Generics in Java, Delphi und C#)
Erlauben Implementierung generischer
„Klassenschablonen“
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
503/543
Elemente mittels Templates /2
Typparameter werden bei der Erzeugung einer konkreten
Variablen durch einen konkreten Typ ersetzt, zum Beispiel
List<int> meineListe;
Setzt zur Übersetzungszeit T auf int
Meist Übersetzung einer separaten Klasse für alle
Typparameter
Beispiel im folgenden Abschnitt: Warteschlangen (Queues
→) mittels Templates
In C++: Standard Template Library (STL) setzt
wiederverwendbare Kollektionstypen als Templates um →
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
504/543
C++ Standard Template Library (STL)
Bietet (vor allem) Kollektionsklassen und einige
Standaralgorithmen
Kollektionsklassen (Auswahl)
list<...>: Liste (geordnet, Duplikate)
vector<...>: dynamisches Array, ähnlich Liste
set<...>: Menge (ungeordnet, kein Duplikate)
multiset<...>: Multimenge (ungeordnet, Duplikate)
map<...>: Kollektion mit assoziativem Zugriff (Schlüssel)
Iterativer Zugriff (Durchlaufen) von Kollektionen über
Iterator-Klassen (→)
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
505/543
C++ STL: Einfaches Beispiel
#include <iostream>
#include <list>
using namespace std;
int main() {
list<int> zahlenliste;
zahlenliste.push_back(7);
zahlenliste.push_back(1);
zahlenliste.push_back(13);
zahlenliste.sort();
list<int>::const_iterator position;
for (position = zahlenliste.begin();
position != zahlenliste.end(); position++)
cout << *position << ” ”;
cout << endl;
return 0;
}
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
506/543
Iteratoren für Kollektionen
Ebenfalls grundlegende Datenstruktur: Hilfsstruktur zum
Durchlaufen einer Kollektion
Daten bestehen nur aus Verweis (Zeiger, Referenz) auf
aktuelle Position (z.B. Knoten) in der Kollektion
Methoden und Operatoren zum Steuern des Durchlaufs
(Anfang, Ende, Weitersetzen, Zurücksetzen, ...)
In C++ STL ebenfalls als Template-Klassen umgesetzt
Verschiedene Iteratoren möglich
Navigationsrichtungen (vor- und rückwärts, nur vorwärts)
Modifikation der Kollektion (z.B. Einfügen, Löschen an
Position) erlaubt
Wahlfreie Positionierung: beliebiges Setzen der Position,
Überspringen von Einträgen, etc.
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
507/543
Zusammenfassung: Kollektionen
Verwaltung von Anzahl von Objekten immer
wiederkehrendes Problem
Unterschiedliche Anforderungen: Duplikate, Ordnung,
Zugriffsmöglichkeiten
→ unterschiedliche Strukturen: Listen, Mengen,
Multimengen, Maps
→ unterschiedliche Implementierungsmöglichkeiten nach
Möglichkeiten der Programmiersprache und
Anforderungen bzgl. Laufzeit und Speicheraufwand
In C++ umgesetzt als Template-Klassen in der STL
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
508/543
Queues und Stacks
Beide Datenstrukturen sind Listen (mit eingeschränkter
Funktionalität) ähnlich und auch oft vergleichbar
implementiert
Aber: haben besondere Bedeutung als Zwischenspeicher
für die Steuerung der Programmlogik
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
509/543
Queues: Warteschlangen
34
17
45
7
22
13
Enqueue
5
Dequeue
FIFO-Prinzip: First In, First Out
Entspricht Liste, bei der nur am Anfang geschrieben/eingefügt
und am Ende gelesen/entfernt werden kann
Zwischenspeicherlösung, welche Daten aufsteigend nach
Dauer seit der letzten Bearbeitung bereitstellt: zuerst älteste
Daten bearbeiten
Zwei wichtige Zugriffsoperationen:
enqueue: Einreihen eines Elementes in die Warteschlange
dequeue: Auslesen eines Elementes aus der
Warteschlange
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
510/543
Verwendung von Queues
Meist auf Ebene des Betriebsystems oder von Protokollen
Synchronisation (Herstellung einer zeitlichen
Reihenfolge) von parallelen Zugriffen auf beschränkte
Ressourcen
Prozesse auf Prozessoren
Lese-/Schreibanforderungen auf Festplatten
Transfer von Daten in Netzwerken
Druckaufträge an einen Drucker
Transaktionen in Datenbanksystemen (→)
...
Asynchrone Kommunikation: Zwischenspeicherung
eingehender Nachrichten/Daten, z.B. Pipe bei
Prozeßkommunikation
Simulation von Produktions- und Transportprozessen
Lastverteilung auf parallel arbeitende Ressourcen über
Kontrolle von Warteschlangen, z.B. Prozessoren in
Multiprozessormaschinen oder einzelnen Servern in
Server Clustern
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
511/543
Stacks: Stapelspeicher
LIFO-Prinzip: Last In, First Out
Entspricht Liste, bei der nur am
Anfang geschrieben/eingefügt
und ebenda gelesen/entfernt
werden kann
Pop
Push
Zwischenspeicherlösung, welche
Daten absteigend nach Dauer
seit der letzten Bearbeitung
bereitstellt: zuerst aktuellste
Daten bearbeiten
Zwei wichtige
Zugriffsoperationen:
push: Ablegen eines
Elementes auf dem Stapel
pop: Entnehmen eines
Elementes vom Stapel
Eike Schallehn, FIN/ITI
17
34
Grundlagen der Informatik für Ingenieure
47
3
22
5
512/543
Verwendung von Stacks
Meist auf Ebene der Speicherverwaltung für Programme
Mikroprozessoren unterstützen Stapelspeicher direkt:
haben Stack Pointer-Register (Zeiger auf oberstes
Stack-Element) und Maschinensprache umfaßt Befehle
PUSH und POP
Programm-Stack: bei Aufruf von Funktionen oder
Sub-Routinen werden aktuelle Daten (Variablen,
Programmzustand) auf einem Stack verwaltet
Rahmen für Daten eines Funktionsaufrufs: Stack Frame
Sequentielle Folge aller Funktionsaufrufe (Stack Frames):
Stack Trace
Syntaktische Analyse von Ausdrücken oder Sätzen (mit
implizit aus Regeln gebildeter hierarchischer Struktur)
Parser als Teil von Compilern und Interpretern zur
Übersetzung von Programmtext
Auswertung algebraischer Terme
...
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
513/543
Queue Implementierung
Implementierung einer einfachen Queue mit
Basisfunktionalität in C++
Verwendet Templates: ermöglicht Wiederverwendung der
Queue für verschiedene Elementtypen
Queue<int> wi;
Queue<char*> wc;
Queue<Student> ws;
Queue<Student*> wsp;
...
Implementierung illustriert auch Grundprinzipien für
Kollektions-Datenstrukturen in C++ (einfach verkettete
Liste)
Vollständiger Quelltext auf der Web-Seite zur Vorlesung
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
514/543
Queue Implementierung: Knoten-Klasse (C++)
template <class T>
class Node {
public :
Node(T e, Node<T>* n) {
element = e;
next = n;
}
void set_next(Node<T>* n) {next = n;}
Node<T>* get_next() { return next;}
T get_element() { return element;}
private :
T element;
Node<T>* next;
};
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
515/543
Queue Implementierung: Queue-Klasse (C++)
template <class T>
class Queue {
public :
Queue() {
first = NULL;
last = NULL;
}
void enqueue(T element);
T dequeue();
bool is_empty() {
return (first == NULL);
}
private :
Node<T>* first;
Node<T>* last;
};
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
516/543
Queue Implementierung: enqueue() (C++)
template <class T>
void Queue<T>::enqueue(T element) {
Node<T>* old_last = last;
last = new Node<T>(element, NULL);
if (old_last == NULL) first = last;
else old_last->set_next(last);
}
Einfügen eines Elementes durch Erzeugen eines neuen
Knotens am Ende der Warteschlange
Spezialfall: Warteschlange war vorher leer
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
517/543
Queue Implementierung: dequeue() (C++)
template <class T>
T Queue<T>::dequeue() {
if (first==NULL)
throw ”Dequeue from empty queue.”;
T e = first->get_element();
Node<T>* old_first = first;
first = first->get_next();
if (first == NULL) last==NULL;
delete old_first;
return e;
}
Rückgabe des Elementes im Knoten am Listenanfang und
dann Knoten löschen
Spezialfall: Warteschlange ist danach leer
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
518/543
Queue Implementierung: main() (C++)
int main() {
Queue<int> w;
w.enqueue(19);
w.enqueue(1);
w.enqueue(42);
w.enqueue(13);
while (! w.is_empty())
cout << w.dequeue() << ” ”;
cout << endl;
return 0;
}
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
519/543
Zusammenfassung: Queues und Stacks
Queue (Warteschlange) und Stack (Stapel) sind
listenähnliche Datenstrukturen
Besondere Bedeutung für Steuerung von
Programmabläufen
Grundprinzipien:
Queue: „Daten, die ich jetzt nicht bearbeiten kann, packe
ich in eine Warteschlange und arbeite diese dann später
systematisch ab“
Stack: „Ich bearbeite erstmal die aktuellsten Daten, und
packe diese bei noch dringenderen Aufgaben auf den
Stapel, von wo ich sie hole, sobald ich mit der aktuellen
Aufgabe fertig bin“
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
520/543
Bäume, Suchbäume und Hash-Tabellen
Im folgenden Fokus auf Datenstrukturen, welche den
assoziativen Zugriff (über einen bestimmten Wert als
Suchkriterium) optimieren
Bäume: Abbildung bzw. Vorberechnung von
Entscheidungen während der Suche in einer geordneten
Menge als hierarchische Datenstruktur
(Entscheidungsbaum, Suchbaum)
Hash-Tabellen: Abbildung von Objekten auf den Speicher
(deren Position darin) wird direkt aus dem Suchkriterium
als Eigenschaft der Objekte abgeleitet
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
521/543
Bäume
Grundlegende Datenstruktur zur
Abbildung einer Hierarchie
Setzt Grundprinzip „Teile und
Herrsche“ (siehe Algorithmen
(→) als Datenstruktur um:
Zerlegung von großen
Datenmengen in kleinere, besser
handhabbare
Grundstruktur: ausgehend von
einer Wurzel (Gesamtheit)
kommt man über verschiedene
Verzweigungen (Unterteilungen)
zu den Blättern (kleinste
Einheiten)
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
522/543
Allgemeine Struktur von Bäumen
Höhe des Baumes
Wurzel
Innere Knoten
1
2
3
4
Blätter
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
523/543
Beispiele: Baumstrukturen in der Informatik
Dateisysteme mit Festplatten, Verzeichnissen, wiederum
darin enthaltenen Verzeichnissen und letztendlich Dateien
Dokumentenstrukturen, z.B. Mit Kapiteln, Abschnitten,
Absätzen
HTML und XML als hierarchische Strukturen
Syntaktische Analyse und Auswertung von
Programmen/Termen: Zerlegung eines Satzes einer
Sprache (Grammatik) enstprechend Regeln in
Teilausdrücke/Wortgruppen bis hin zu kleinsten Einheiten
(Atome, Terminale)
Suchbäume als Indexe zum schnellen assoziativen
Zugriff über Schlüsselwerte
Datenbanksysteme
Allgemein: Suche nach Worten in Texten
Speziell: Suchmaschinen im World Wide Web
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
524/543
Binäre Suchbäume
12
5
2
17
15
11
14
19
18
21
Binär = Verzweigungsgrad 2: jeder Knoten hat maximal 2
Kindknoten
Jeder Knoten speichert einen Suchschlüssel und
repräsentiert damit folgende Entscheidung:
Ist der gesuchte Wert gleich dem Schlüssel → GEFUNDEN
Ist der Wert kleiner, gehe zum linken Kindknoten
Ist der Wert größer, gehe zum rechten Kindknoten
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
525/543
Binäre Suchbäume: Suchen und Einfügen
Suchen und Einfügen prinzipiell ähnlich:
Algorithmus startet an der Wurzel
In jedem Knoten: wenn Schlüssel nicht gefunden,
verzweige zu einem Kindknoten
Auf Blattebene:
Einfügen: neuen Kindknoten erzeugen
Suchen: Worst Case - Schlüssel nicht gefunden
Aufwand für beide Operationen dominiert vom Durchlaufen
des Weges von der Wurzel bis zum Blatt, d.h. Höhe des
Baumes an dieser Stelle
Balancierter Baum (→): Baum ist so gleichmäßig gefüllt,
dass Weg von der Wurzel zu Blättern überall möglichst
gleich
Bei balanciertem Baum mit n = 2k Elementen ist die Höhe
des Baumes ca. h = k = log2 n
Durchschnittlicher Aufwand für beide Operationen damit:
O(log n)
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
526/543
Balancierte Binäre Suchbäume: Aufwand
Eike Schallehn, FIN/ITI
Maximale
#Knoten
Höhe
= Aufwand
1= 2^1-1
3=2^2-1
7=2^3-1
15=2^4-1
31=2^5-1
63=2^6-1
127=2^7-1
255=2^8-1
511
1023
...
n
1
2
3
4
5
6
7
8
9
10
...
O(log n)
Grundlagen der Informatik für Ingenieure
527/543
Binärbaum: Beispielimplementierung (C++)
Einfach Implementierung bestehend aus Klassen für
Knoten mit Schlüssel und Verweisen auf Kindknoten
Binärbaum mit Verweis auf Wurzeln
Implementiert nur Suchen und Einfügen
Eigentliche Daten werden nicht eingetragen, nur Schlüssel
vom Typ int
Hinweise
Verwendet friend-Klassen: umgehen Kapselung, indem
befreundete Klassen auf privat-Daten zugreifen können
Vollständiger Quelltext auf der Web-Seit zur Vorlesung
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
528/543
Binärbaum: Knotenklasse
class Node {
friend class BinaryTree;
private :
int key;
Node* left;
Node* right;
Node(int k) { ... }
bool search(int k);
void insert(int k);
void print(int level);
};
Definiert rekursive Methoden zum Einfügen und Suchen →
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
529/543
Binärbaum: Baumklasse
class BinaryTree {
public :
BinaryTree() {
root = NULL;
}
bool search(int key);
void insert(int key);
void print();
private :
Node* root;
};
Methoden zum Einfügen und Suchen als Einstiespunkt für
Rekursion ausgehend von der Wurzel
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
530/543
Binärbaum: Einfügen
void Node::insert(int k) {
if (k==key) return;
if (k<key)
if (left != NULL) left->insert(k);
else left = new Node(k);
if (k>key)
if (right != NULL) right->insert(k);
else right = new Node(k);
}
Schlüssel vorhanden → Einfügen beenden
Andernfalls, falls möglich im linken (neuer Schlüssel
kleiner) oder rechten Teilbaum einfügen (neuer Schlüssel
größer)
Falls kein Kindknoten links oder rechts existiert: neuen
Kindknoten mit neuem Schlüssel erzeugen
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
531/543
Entartung von Bäumen
Balanciertheit wichtige Eigenschaft von Bäumen: garantiert
effiziente Ausführung der Operationen mit O(log n)
Ohne weiteres aber keine garantierte Eigenschaft
Abhängig zum Beispiel von Einfügereihenfolge
Schlechte Einfügereihenfolge kann zu Entartung des
Baumes führen
Im schlimmsten Fall wird Baum zu Liste
Operationen dann mit wesentlich schlechterer
Laufzeitkomplexität O(n): sequentielle Suche
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
532/543
Beispiel: Entartung von Bäumen
1
4
2
2
1
6
3
5
3
4
7
5
6
Balancierter Baum
bei Einfügereihenfolge
4, 2, 6, 3, 1, 7, 5
Eike Schallehn, FIN/ITI
Entarteter Baum
bei Einfügereihenfolge
1, 2, 3, 4, 5, 6, 7
Grundlagen der Informatik für Ingenieure
7
533/543
Balancierte Bäume
Sicherstellung einer relativen Ausgeglichenheit bei binären
Bäumen durch spezielle Modifikationsoperationen
(Einfügen, Löschen)
Angabe eines speziellen Balancekriteriums, z.B.
AVL-Baum: in jedem Knoten darf der Höhenunterschied
zwischen linkem und rechten Teilbaum maximal 1 sein!
Wird Balancekriterium verletzt, werden Verfahren zur
lokalen Reorganisation des Baumes angewandt
→ AVL-Bäume, Rot-Schwarz-Bäume
Vollständige Ausgeglichenheit möglich durch Knoten mit
variablem Verzweigungsgrad
Mehr als 1 Schlüssel pro Knoten
Verweis auf Kindknoten mit Werten zwischen 2 Schlüsseln
(Bereich)
Knotengröße kann an Speicherstrukturen angepasst
werden (z.B. Blöcke der Festplatte)
→ B-Bäume
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
534/543
... geht es besser als O(log n)?
Assoziative Zugriffe (Suche über einen Schlüsselwert) mit
Bäumen mit logarithmischem Aufwand O(log n)
D.h. nur ein zusätzlicher Suchschritt notwendige für jede
Verdopplung der Größe der Datenmenge, in der gesucht
wird
Geht es noch besser?
Ja, Hash-Tabellen können Schlüsselzugriff (unter
bestimmten Bedingungen) mit konstantem Aufwand O(1)
umsetzen
D.h. egal wie groß die Datenmenge, das Finden der
richtigen Daten geht immer gleich schnell!
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
535/543
Hash-Tabellen
Auch Streuwerttabelle oder Hash Map
Grundprinzip: Berechnung der Position der Daten im
Speicher (strukturiert als Tabelle) aus dem Schlüsselwert
key
Berechnung der Position beim Einfügen
Berechnung der Position beim Suchen
Erfordert Vorreservierung eines Speicherbereichs der
Größe M → M meist sehr groß, ab mehreren Tausend
Einträgen
Positionen 0 . . . M − 1 in Speicherbereich werden auch
Hash Buckets genannte
Berechnung der Position über spezielle Hash-Funktion
h : dom(key) → {0, 1, . . . , M − 1}
Wahlfreier Zugriff im RAM und auf Festplatte ermöglicht
direkten Zugriff auf an dieser Stelle gespeicherte Daten
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
536/543
Einfügen in Hash-Tabellen
Zu speichernde
Objekte
Hash-Tabelle
Student Udo Urban
MatrNr 170480
0
1
2
Student Eva Lange
MatrNr 175783
156324, Max Müller
170480, Udo Urban
3
4
Student Max Müller
MatrNr 156324
5
6
175783, Eva Lange
Hash-Funktion
h(MatrNr)=MatrNr % 7
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
537/543
Suchen in Hash-Tabellen
Hash-Tabelle
0
Suche nach
Matrikelnummer:
1
170480
3
2
156324, Max Müller
170480, Udo Urban
4
5
6
175783, Eva Lange
Hash-Funktion
h(MatrNr)=MatrNr % 7
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
538/543
Hash-Funktionen
Wertebereich ist (beim hier betrachteten statischen
Hashen) durch Speichergröße M bestimmt
Problem: Hash-Funktion ist nicht injektiv, d.h.
verschiedene Schlüssel können auf eine Adresse
abgebildet werden → Kollisionen!
Gute Hash-Funktionen erzeugen möglichst zufällig
gestreute Speicherzuordnung und machen dadurch
Kollisionen unwahrscheinlich
Meist umgesetzt durch
Kombination von verschiedenen Operationen mit möglichst
zufälligem Ergebnis, z.B. Bit-Verschiebeoperationen
Am Ende Modulodivision durch M → Rest ist Hash-Wert
Primzahlen als Parameter der Hash-Funktion sorgen für
gute, zufällige Verteilung
Kollisionen lassen sich aber meist nicht völlig vermeiden →
erfordern Kollisionsbehandlung
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
539/543
Hash-Tabellen: Kollisionsbehandlung
Verkettete Liste: der Eintrag in einer Hash-Tabelle verweist auf
eine Liste der dorthin gehashten Daten
Kann bei schlechter Hash-Funktion mit vielen
Kollisionen zu Entartung führen
Mehraufwand für Speicherung
Sondieren: (engl. Probing) ist der Hash Bucket bereits belegt,
wird nach einem einfachen Muster ein anderer
Platz gesucht
Z.B. lineares Sondieren: testen ob folgende
Hash Bucket frei ist, erster freier wird genutzt
Doppeltes Hashen: ist der Hash Bucket belegt, wird (ggf.
wiederholt) ein weiterer Hash-Wert berechnet und
diese Position getestet
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
540/543
Implementierung von Hash-Tabellen
(Bisher besprochene) statische Hash-Verfahren:
vordefinierte Speichergröße kann effizient über Array
umgesetzt werden
Dynamische Hash-Verfahren können den benutzten
Speicherbereich zur Laufzeit Vergrößern → z.B. durch
verkettete Arrays
Kollisionsbehandlung durch verkettet Liste erfordert
zusätzliche Datenstruktur
Sondieren und Doppeltes Hashen Erfordern aufwändigere
Operationsimplementierungen
Beispielimplementierung auf der Web-Seite zur Vorlesung
Einfaches statisches Hashverfahren mit linearem Sondieren
In der Vorlesung nicht vorgestellt
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
541/543
Nachteile von Hashtabellen
Keine Ordnung der Elemente: in Bäumen sind Elemente stets
geordnet gespeichert – geordnete Ausgabe aus einer
Hash-Tabelle erfordert zusätzliche Sortierung
Vorreservierung des Speichers notwendig: z.B. über Arrays,
die zur Vermeidung von Überlauf und Kollisionen ggf. weit
überdimensioniert sind (Trade-off: Speichereffizienz vs.
Laufzeiteffizienz)
Überlauf möglich: bei einigen statischen Verfahren (z.B. bei
Überlaufbehandlung durch Sondieren, nicht bei verketteter Liste)
kann die Hash-Tabelle tatsächlich vollständig gefüllt werden, so
dass keine weiteren Daten eingetragen werden können
Aufwand für Dynamik: Verfahren, welche zur Vermeidung von
Überläufen und Kollisionen, die Hash-Tabelle dynamisch
wachsen lassen, nähern sich mit ihrem Laufzeitverhalten
Bäumen an
Aufwand für Überlaufbehandlung: auch bei vielen Kollisionen,
z.B. durch schlechte Hash-Funktion, verschlechtert sich die
Laufzeitkomplexität
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
542/543
Zusammenfassung: Datenstrukturen
Klassische Datenstrukturen bieten Standardlösungen für
effiziente Bearbeitung von Daten
Wichtigste hier vorgestellt:
Kollektionsdatentypen wie Listen, Mengen und
Multimengen zur Verwaltung einer Sammlung
zusammengehörender Objekte
Queues und Stacks zur Steuerung der
Berabeitungsreihenfolge von Datenobjekten
Bäume und Hash-Tabellen für schnelles Suchen von
Daten über einen Schlüsselwert
Oft in Form von generischen Klassenbibliotheken
umgesetzt, z.B. STL in C++
Eigene Implementierung durch Verwendung von
Typkonstruktoren (Arrays, Structs, Klassen) und Zeiger
sowie Klassenschablonen (Templates, Generics) möglich
Eike Schallehn, FIN/ITI
Grundlagen der Informatik für Ingenieure
543/543
Herunterladen