Datenstruktur

Werbung
Teil VII
Grundlegende Datenstrukturen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–1
Grundlegende Datenstrukturen
Einführung
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–2
Grundlegende Datenstrukturen
Einführung
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–3
Grundlegende Datenstrukturen
Einführung
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–4
Grundlegende Datenstrukturen
Einführung
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–5
Grundlegende Datenstrukturen
Einführung
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–6
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–7
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
Überblick: Kollektionsdatentypen
Kollektionstyp
Array / Feld
Set / Menge
Bag / Multimenge
List / Liste
Map, Hash Table
Eike Schallehn
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
2009/2010
7–8
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–9
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–10
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–11
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–12
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–13
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–14
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–15
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–16
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–17
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–18
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–19
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–20
Grundlegende Datenstrukturen
Datenstrukturen für Kollektionen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–21
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–22
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–23
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–24
Grundlegende Datenstrukturen
Queues und Stacks
Stacks: Stapelspeicher
LIFO-Prinzip: Last In, First Out
Entspricht Liste, bei der nur am
Anfang geschrieben/eingefügt und
ebenda gelesen/entfernt werden
kann
Zwischenspeicherlösung, welche
Daten absteigend nach Dauer seit
der letzten Bearbeitung bereitstellt:
zuerst aktuellste Daten bearbeiten
Pop
Push
Zwei wichtige Zugriffsoperationen:
◮ push: Ablegen eines Elementes
auf dem Stapel
◮ pop: Entnehmen eines
Elementes vom Stapel
Eike Schallehn
17
34
Grundlagen der Informatik für Ingenieure
47
3
22
5
2009/2010
7–25
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–26
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–27
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–28
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–29
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–30
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–31
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–32
Grundlegende Datenstrukturen
Queues und Stacks
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–33
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–34
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–35
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
Allgemeine Struktur von Bäumen
Höhe des Baumes
Wurzel
Innere Knoten
1
2
3
4
Blätter
Eike Schallehn
Grundlagen der Informatik für Ingenieure
2009/2010
7–36
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–37
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–38
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–39
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
Balancierte Binäre Suchbäume: Aufwand
Eike Schallehn
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
2009/2010
7–40
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–41
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–42
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–43
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–44
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–45
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Entarteter Baum
bei Einfügereihenfolge
1, 2, 3, 4, 5, 6, 7
Grundlagen der Informatik für Ingenieure
2009/2010
7
7–46
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–47
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
... 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
Grundlagen der Informatik für Ingenieure
2009/2010
7–48
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–49
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
Einfügen in Hash-Tabellen
Zu speichernde
Objekte
Hash-Tabelle
Student Udo Urban
MatrNr 170481
0
1
2
Student Eva Lange
MatrNr 175783
156324, Max Müller
170481, Udo Urban
3
4
Student Max Müller
MatrNr 156324
5
6
175783, Eva Lange
Hash-Funktion
h(MatrNr)=MatrNr % 7
Eike Schallehn
Grundlagen der Informatik für Ingenieure
2009/2010
7–50
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
Suchen in Hash-Tabellen
Hash-Tabelle
0
Suche nach
Matrikelnummer:
1
170481
3
2
156324, Max Müller
170481, Udo Urban
4
5
6
175783, Eva Lange
Hash-Funktion
h(MatrNr)=MatrNr % 7
Eike Schallehn
Grundlagen der Informatik für Ingenieure
2009/2010
7–51
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–52
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–53
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–54
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–55
Grundlegende Datenstrukturen
Bäume, Suchbäume und Hash-Tabellen
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
Grundlagen der Informatik für Ingenieure
2009/2010
7–56
Herunterladen