2.2k likes | 2.48k Views
Informatik 2 Datenstrukturen. Prof. Dr.-Ing. Holger Vogelsang holger.vogelsang@hs-karlsruhe.de. Inhaltsverzeichnis. Abstrakte Datentypen (3) Datenstrukturen in Java (11) Elementare Datenstrukturen (14) Iteratoren (32) Streams (48) Hashtabellen (57) Bäume (103) Graphen (192).
E N D
Informatik 2Datenstrukturen Prof. Dr.-Ing. Holger Vogelsang holger.vogelsang@hs-karlsruhe.de
Inhaltsverzeichnis • Abstrakte Datentypen (3) • Datenstrukturen in Java (11) • Elementare Datenstrukturen (14) • Iteratoren (32) • Streams (48) • Hashtabellen (57) • Bäume (103) • Graphen (192) Informatik 2 - Datenstrukturen
Abstrakte Datentypen Übersicht Grafische Oberflä- chen Übersicht Layouts Ereignisse Widgets Grafik- operationen Grafik- widgets Effekte, Animationen Offene Punkte Daten- strukturen ADTs Datenstrukturen in Java Elementare Datenstrukturen Iteratoren, Stream Hash- tabellen Bäume Graphen Typinfo., I/O Annota- tionen Ein-, Ausgabe Laufzeit- typinfo. Entwurf Prinzipien Verbindung von Modulen Spring OSGi Informatik 2 - Datenstrukturen
Abstrakte Datentypen Übersicht • Bisher: • Einführung in objektorientierte Programmierung • Einfache Datenstrukturen wie Array, Vektor und Liste • Jetzt: • Festlegung von Schnittstelle und Funktionalität einer Datenstruktur, ohne eine konkrete Implementierung zu verwenden Definition: Abstrakter Datentyp Ein abstrakter Datentyp (ADT) ist ein Datentyp (eine Menge von Werten und eine Sammlung von Operationen auf diesen Werten), der nur über eine Schnittstelle zugänglich ist. Ein ADT kann bei identischer Funktionalität unterschiedliche mögliche Implementierungen besitzen. Informatik 2 - Datenstrukturen
Abstrakte Datentypen Übersicht • Eine ADT-Spezifikation besteht aus einer Signatur und Axiomen (hier stark vereinfacht dargestellt, die mathematischen Begriffe wurden teilweise nicht verwendet). • Signatur ∑ = (S, Ω) mit • S = Die Menge von Datentypen, die der ADT verwendet. Einer der Datentypen wird in der Regel durch den ADT neu definiert. Die anderen existieren bereits. • Ω = Die Menge von Methoden und Konstanten des ADT. • Axiome legen die Semantik und damit das Verhalten des ADT unabhängig von einer konkreten Implementierung fest. • In diesen Unterlagen werden teilweise Beispiele aus dem Buch „Algorithmen und Datenstrukturen“ von Saakeund Sattler übernommen. Die Darstellung der ADTs entspricht auch der Syntax aus dem Buch. Informatik 2 - Datenstrukturen
Abstrakte Datentypen Beispiel: Liste • Unvollständiger ADT für eine Liste List von Elementen des Datentyps T. type List(T) importNat operators [] List _:_ : T List List addFirst : List T List getFirst : List T getTail : List List size : List Nat axiomsl : List, x : T getTail(addFirst(l, x)) = l getFirst(addFirst(l, x)) = x getFirst(x : l) = x getTail(x : l) = l size([]) = 0 size(x : l) = succ(size(l)) []erzeugt eine neue, leere Liste _:_Konstruktions- vorschrift (neuer Operator) x : lElement x und weitere Listenelemente in l succentstammt ADT für natürliche Zahlen Informatik 2 - Datenstrukturen
Abstrakte Datentypen Beispiel: Liste • Mögliche Listen: • [] leere Liste • 1 : [] Liste mit dem Element 1 • 1 : 2 : 3 : 4 : [] Liste mit den Elementen 1 bis 4 • Deutlich erkennbar: Das Wissen über die konkrete Implementierung der Liste ist für die Anwendung nicht erforderlich. • In einer Programmiersprache: Schnittstelle der Klasse (öffentliche Methoden und Datentypen) sowie die Dokumentation des Verhalten sind erforderlich. • Die Art der Implementierung ist unwichtig (sofern sie das Laufzeitverhalten nicht beeinflusst). • Wozu dient das Wissen über ADTs? • ADT könnte in Java eine Schnittstelle (ein interface) sein. • Die konkrete Implementierung implementiert die Schnittstelle. • Es lässt sich prima „auf der Schnittstelle“ arbeiten. Informatik 2 - Datenstrukturen
Abstrakte Datentypen Anwendung eines ADT Beispiel ADT List und konkrete Java-Umsetzung der Operatoren type List(T) importNat operators [] List _:_ : T List List addFirst: List T List getFirst : List T getTail : List List size: List Nat axiomsl : List, x : T getTail(addFirst(l, x)) = l getFirst(addFirst(l, x)) = x getFirst(x : l) = x getTail(x : l) = l size([]) = 0 size(x : l) = succ(size(l)) T: class <<interface>> List +add(int i, e: T): boolean +get(index: int): T +remove(index: int): T +size(): int T: class T: class LinkedList ArrayList +add(int i, e: T): boolean +get(index: int): T +remove(index: int): T +size(): int +add(int i, e: T): boolean +get(index: int): T +remove(index: int): T +size(): int Vektor Verkettete Liste Informatik 2 - Datenstrukturen
Abstrakte Datentypen Anwendung eines ADT Beispiel ADT List und konkrete Java-Umsetzung der Axiome type List(T) importNat operators [] List _:_ : T List List addFirst: List T List getFirst : List T getTail : List List size: List Nat axiomsl : List, x : T getTail(addFirst(l, x)) = l getFirst(addFirst(l, x)) = x getFirst(x : l) = x getTail(x : l) = l size([]) = 0 size(x : l) = succ(size(l)) z.B. als Dokumentation oder zur Validierung einer Implementierung Informatik 2 - Datenstrukturen
Abstrakte Datentypen ADT: Beschreibung der Axiome • Die Axiome können durch nahezu beliebige „Sprachen“ beschrieben werden. • Komplexere Aussagen sind z.B. mit OCaml (funktionale Programmiersprache, siehe http://caml.inria.fr/) möglich soll hier nicht näher vertieft werden. Informatik 2 - Datenstrukturen
Datenstrukturen in Java Übersicht Grafische Oberflä- chen Übersicht Layouts Ereignisse Widgets Grafik- operationen Grafik- widgets Effekte, Animationen Offene Punkte Daten- strukturen ADTs Datenstrukturen in Java Elementare Datenstrukturen Iteratoren, Stream Hash- tabellen Bäume Graphen Typinfo., I/O Annota- tionen Ein-, Ausgabe Laufzeit- typinfo. Entwurf Prinzipien Verbindung von Modulen Spring OSGi Informatik 2 - Datenstrukturen
Datenstrukturen in JavaÜbersicht • Vereinfachte Übersicht über die Collections-Klassen in Java Informatik 2 - Datenstrukturen
Datenstrukturen in JavaSchnittstellen • Iterable<E>: Über die Datenstruktur kann direkt iteriert werden siehe Iteratoren. • Collection<E>: Gruppe von Elementen, Duplikate können erlaubt sein • List<E>: Collection mit einer Ordnung, Indexzugriff ist erlaubt (möglicherweise ineffizient) • RandomAccess: Leere Schnittstelle, der Indexzugriff ist mit konstanter Zeit möglich. • Queue<E>: spezielle Queue-Operationen vorhanden • Deque<E>: Queue mit Einfüge- und Löschoperationen an Anfang und Ende • Set<E>: Menge von Elementen ohne Duplikate • SortedSet<E>: Menge mit einer Totalordnung der Elemente (anhand ihrer natürlichen Ordnung oder anhand eines Vergleichs-Objektes) • NavigableSet<E>: SortedSet mit Methoden, um kleinere oder größere Elemente zu finden • Map<K,V>: Bildet Schlüssel-Objekte (K) auf Werte (V) ab. • SortedMap<K,V>: Eine Map mit einer Totalordnung der Elemente • NavigableMap<K,V>: SortedMapmit Methoden, um kleinere oder größere Schlüssel zu finden. Informatik 2 - Datenstrukturen
Elementare Datenstrukturen Übersicht Grafische Oberflä- chen Übersicht Layouts Ereignisse Widgets Grafik- operationen Grafik- widgets Effekte, Animationen Offene Punkte Daten- strukturen ADTs Datenstrukturen in Java Elementare Datenstrukturen Iteratoren, Stream Hash- tabellen Bäume Graphen Typinfo., I/O Annota- tionen Ein-, Ausgabe Laufzeit- typinfo. Entwurf Prinzipien Verbindung von Modulen Spring OSGi Informatik 2 - Datenstrukturen
Elementare DatenstrukturenÜbersicht in Java • Elementare Datenstrukturen Informatik 2 - Datenstrukturen
Elementare DatenstrukturenVektor – Prinzip • Die Klassen ArrayList<E> und Vector<E> verwalten dynamisch beliebig viele Objekte. • Die Anordnung der Objekte erfolgt sequentiell. • Die interne Implementierung erfolgt durch ein Array. • Der Vektor besitzt eine Referenz auf den Speicherbereich. • Ein Vektor eignet sich besonders für einen schnellen freien Zugriff über Indizes auf die Elemente. • Der Indexzugriff erfolgt immer geprüft. • Vector ist im Gegensatz zu ArrayList thread-sicher und damit langsamer. E: class ArrayList ArrayList size -values[*]: E -size: int Extra Platz 0 1 2 3 4 5 6 7 Informatik 2 - Datenstrukturen
Elementare DatenstrukturenBeispiel zu ArrayList • Beispiel: importjava.util.ArrayList; publicclassArrayListTest { publicstaticvoidmain(String[] args) { ArrayList<Integer> contents = newArrayList<>(10); for(int i = 0; i < 10; i++) { contents.add(i * i); } int v = contents.get(12); // Geprüfter Zugriff --> // Abfangen der Fehler System.out.println(contents.size()); System.out.println(contents.contains(2)); } } Informatik 2 - Datenstrukturen
Elementare DatenstrukturenArrayList und Vektor in Java • Beide implementieren RandomAccess: Indexzugriff in konstanter Zeit Informatik 2 - Datenstrukturen
Elementare Datenstrukturen Vektor – Aufwandsabschätzungen Aufwandsabschätzungen für die Vektor-Klassen Informatik 2 - Datenstrukturen
Elementare DatenstrukturenListe: Prinzip • Prinzip einer einfach verketteten Liste: • Die Liste besitzt einen Kopf und ein Ende. • Jeder Listeneintrag verweist auf seinen Nachfolger. • Jeder Listeneintrag beinhaltet die Nutzdaten. LinkedList last Listelement Listelement Listelement first value value value E: class E: class first 0, 1 LinkedList Listelement 0, 1 next -value: E last 0, 1 Informatik 2 - Datenstrukturen
Elementare DatenstrukturenListe: Prinzip • Prinzip einer doppelt verketteten Liste: • Die Liste besitzt einen Kopf und ein Ende. • Jeder Listeneintrag verweist auf seinen Nachfolger und Vorgänger • Jeder Listeneintrag beinhaltet die Nutzdaten. LinkedList last Listelement Listelement Listelement first value value value E: class E: class first 0, 1 LinkedList Listelement 0, 1 next -value: E last 0, 1 0, 1 prev Informatik 2 - Datenstrukturen
Elementare DatenstrukturenListe in Java • LinkedList implementiert nicht RandomAccess: Indexzugriff nicht in konstanter Zeit! Informatik 2 - Datenstrukturen
Elementare DatenstrukturenListe – Aufwandsabschätzung Informatik 2 - Datenstrukturen
Elementare Datenstrukturen Queue – Prinzip • Prinzip einer Queue (Warteschlange): • Daten werden in einer Queue am Ende mit offereingetragen und am Anfang der Queue mit pollentfernt Warteschlange (häufig auch push/pop). • Es gibt einige Container-Klassen, die Queue-Funktionalität einsetzen. Beispiel: LinkedList. • Einsatzgebiete • einfaches Nachrichtensystem (Nachricht ablegen = offer, Nachricht abholen = poll). • allgemeine asynchrone Kommunikation zwischen Auftragnehmer und Auftraggeber Queue 0 1 2 3 Informatik 2 - Datenstrukturen
Elementare DatenstrukturenQueue in Java • LinkedList implementiert Queue Informatik 2 - Datenstrukturen
Elementare Datenstrukturen Queue in Java • Die Methoden gibt es doppelt (aus Queue und Deque): Informatik 2 - Datenstrukturen
Elementare Datenstrukturen Queue – Prinzip • Arbeitsweise einer Queue an einem Beispiel. • Initialzustand: • offer(E4): • poll(): Queue E2 E1 E3 0 1 2 Queue offer E4 E2 E1 E3 0 1 2 3 Queue poll E4 E2 E3 0 1 2 Informatik 2 - Datenstrukturen
Elementare Datenstrukturen Stack – Prinzip • Prinzip eines Stacks (Stapel): • Daten werden in einem Stack am Ende mit offereingetragen und ebenfalls am Ende mit pollentfernt Stapel(häufig auch push/pop). • Einsatzgebiete u.a.: • Zwischenspeicherung von Objekten, wenn eine Rekursion zu einer Iteration aufgelöst wird. • Text-Parser. Stack 0 1 2 3 Informatik 2 - Datenstrukturen
Elementare DatenstrukturenStack in Java • Es gibt eine Stack-Klasse, die aber nicht optimal ist. Besser: Klasse, dieDequeimplementiert. Informatik 2 - Datenstrukturen
Elementare DatenstrukturenStackin Java • Die Methoden gibt es doppelt (aus Queue und Deque): Informatik 2 - Datenstrukturen
Elementare Datenstrukturen Stack – Prinzip • Arbeitsweise eines Stacks an einem Beispiel. • Initialzustand: • offer(E4): • pollLast(): Stack E2 E1 E3 0 1 2 Stack offer E4 E2 E1 E3 0 1 2 3 Stack pollLast E3 E1 E2 0 1 2 Informatik 2 - Datenstrukturen
Iteratoren Übersicht Grafische Oberflä- chen Übersicht Layouts Ereignisse Widgets Grafik- operationen Grafik- widgets Effekte, Animationen Offene Punkte Daten- strukturen ADTs Datenstrukturen in Java Elementare Datenstrukturen Iteratoren, Stream Hash- tabellen Bäume Graphen Typinfo., I/O Annota- tionen Ein-, Ausgabe Laufzeit- typinfo. Entwurf Prinzipien Verbindung von Modulen Spring OSGi Informatik 2 - Datenstrukturen
Iteratoren Motivation • Wie lässt sich ein Algorithmus schreiben, der unabhängig von einer konkreten Datenstruktur arbeiten kann? • Wie können beliebig viele Algorithmen quasi parallel eine unbekannte Datenstruktur bearbeiten? Informatik 2 - Datenstrukturen
Iteratoren Konzept • Problem: Bisher werden Listen oder Vektoren durch eine Schleife, die direkt auf die Elemente des Containers zugreift, durchlaufen. Wie kann aber ein Algorithmus unabhängig von der Klasse (dem Container) geschrieben werden? • Ziel: Konstruktion eines Algorithmus unabhängig von der konkreten Klasse (dem Container). • Lösung: Iteratoren dienen als Bindeglied zwischen den Containern und Algorithmen auf Containern Prinzip „Umkehr der Abhängigkeiten“! • Iteratoren sind abstrakte Datentypen, mit deren Hilfe auf eine Folge von Objekten zugegriffen werden kann. • Ein Iteratorverweist immer auf ein Objekt innerhalb einer Folge von Objekten. • Die Vorlesung behandelt Iteratoren nicht vollständig. Informatik 2 - Datenstrukturen
Iteratoren Konzept • Mögliche Vektor- und Listenimplementierungen mit Sortierung der Elemente. • Mit einem Iterator können alle Elemente in ihrer Sortierreihenfolge besucht werden. ArrayList Extra Platz sequentielles Durchlaufen LinkedList last first sequentielles Durchlaufen Informatik 2 - Datenstrukturen
Iteratoren Konzept • Iterator als Bindeglied zwischen Algorithmus und Datenstruktur: ArrayList Zugriff erzeugt Zugriff auf die Datenstruktur über eine einheitliche Schnittstelle Algorithmus erzeugt Zugriff first last LinkedList Informatik 2 - Datenstrukturen
Iteratoren Funktionsweise • Jede Datenstruktur bietet eigene Iteratoren, die eine der beiden folgenden Schnittstellen implementieren: normaler Iterator, um eine Collection vom Anfang bis zum Ende zu durchlaufen • Iterator, um eine Listvorwärts und rückwärts zu • durchlaufen • erlaubt das Ersetzen von Elementen • ermöglicht das Auslesen des aktuellen Indexes Informatik 2 - Datenstrukturen
Iteratoren Funktionsweise • Jede Datenstruktur hat Methoden, die die Iteratorobjekteerzeugen: Informatik 2 - Datenstrukturen
importjava.util.ArrayList; importjava.util.Iterator; importjava.util.ListIterator; publicclassIteratorTest{ publicstaticvoidprint( Iterator<?> iter) { while(iter.hasNext()) { System.out.println(iter.next()); } } publicstatic <E> voidmodify( ListIterator<? super E> iter, E value) { while(iter.hasNext()) { iter.next(); iter.set(value); } } publicstaticvoidmain( String[] args) { ArrayList<String> source= newArrayList<>(); source.add("Hallo 1"); source.add("Hallo 2"); source.add("Hallo 3"); source.add("Hallo 4"); print(source.iterator()); modify(source.listIterator(), "----"); } } Iteratoren Beispiel Informatik 2 - Datenstrukturen
importjava.util.ArrayList; importjava.util.Iterator; importjava.util.ListIterator; publicclassIteratorTest { publicstatic <E> voidcopy( ListIterator<? super E> dest, ListIterator<? extends E> source) { while(source.hasNext()) { // Im Ziel überschreiben? if(dest.hasNext()) { dest.next(); dest.set(source.next()); } // Anhängen, da Ziel kürzer else{ dest.add(source.next()); } } } publicstaticvoidmain( String[] args) { ArrayList<String> source = newArrayList<>(); source.add("Hallo 1"); source.add("Hallo 2"); source.add("Hallo 3"); source.add("Hallo 4"); ArrayList<String> dest = newArrayList<>(); copy(dest.listIterator(), source.listIterator()); } } Iteratoren Weiteres Beispiel kopiert von ArrayList in ArrayList Informatik 2 - Datenstrukturen
copyarbeitet auch mit LinkedList, Vector, und anderen Datentypen. publicstaticvoidmain( String[] args) { LinkedList<String> source = newLinkedList<>(); source.add("Hallo 1"); source.add("Hallo 2"); source.add("Hallo 3"); source.add("Hallo 4"); LinkedList<String> dest = newLinkedList<>(); copy(dest.listIterator(), source.listIterator()); } } copy kann auch zwischen unterschiedlichen Containern kopieren. publicstaticvoidmain( String[] args) { ArrayList<String> source = newArrayList<>(); source.add("Hallo 1"); source.add("Hallo 2"); source.add("Hallo 3"); source.add("Hallo 4"); LinkedList<String> dest = newLinkedList<>(); copy(dest.listIterator(), source.listIterator()); } } Iteratoren Weiteres Beispiel – Variante 2 Im SDK wird aber eher mit Collection und List statt mit Iteratoren gearbeitet. Informatik 2 - Datenstrukturen
Iteratoren Bedeutung von Iteratoren: Beispiel • Die folgenden Klassen verwalten ein einfaches Dateisystem direkt im Hauptspeicher des Computers. File Directory 0..* subdirectories -name: String -access: int -name: String -access: int -contents: byte[*] files 0..* parent 0, 1 // Eine Datei im Dateisystem publicclassFile { private String name; // Name private intaccess; // Rechte private byte[] contents; // Inhalt public File(String name, intaccess, byte[] contents){} public boolean equals( Object other){} // } // Verzeichnis im Dateisystem publicclassDirectory { private String name; private Directory parent; // Vater private LinkedList<Directory> subdirectories; private LinkedList<File> files; private intaccess; // } Informatik 2 - Datenstrukturen
Iteratoren Bedeutung von Iteratoren: Beispiel • Es ergibt sich ein Baum aus Verzeichnissen, in denen jeweils eine Anzahl von Dateien liegen kann. • Ziel: Schreiben einiger Methoden der Directory-Klasse, die über Iteratoren auf den Baum zugreifen. Zählen aller Dateien • Methode der Klasse Directory, die die Anzahl der Dateien in dem Verzeichnis sowie seinen Unterverzeichnissen ermittelt. public intcountFiles() { intsize = files.size(); for (Iterator<Directory> iter = subdirectories.iterator(); iter.hasNext();) { Directory currentDirectory = iter.next(); size += currentDirectory.countFiles(); } returnsize; } Informatik 2 - Datenstrukturen
Iteratoren Bedeutung von Iteratoren: Beispiel Suchen einer Datei • Methode der Klasse Directory, die nur in diesem Verzeichnis (nicht in seinen Unterverzeichnissen) eine Datei sucht. Doppelte Dateinamen kommen nicht vor. public booleancontainsFile(File file) { for (Iterator<File> iter = files.iterator(); iter.hasNext(); ) { if (iter.next().equals(file)) { return true; } } return false; } Informatik 2 - Datenstrukturen
Iteratoren Bedeutung von Iteratoren • Abstrakte Zugriffe auf Datenstrukturen (nicht auf konkrete Collection-Klassen): • Iteratoren • Methoden der Schnittstellen List und Collection • Viele Algorithmen sind auch als statische Methoden in der Klasse Collections vorhanden (sortieren usw.). • Diese arbeiten fast immer auf den Schnittstellen List und Collection. Informatik 2 - Datenstrukturen
Iteratoren Eine Auswahl an Algorithmen der Klasse Collections Informatik 2 - Datenstrukturen
Iteratoren Eine Auswahl an Algorithmen der Klasse Collections Informatik 2 - Datenstrukturen
Streams Motivation • Mit Iteratoren lassen sich Datenstrukturen durchlaufen. Geht das auch eleganter? • Wie kann das Durchlaufen von den Aktionen auf den einzelnen Elementen entkoppelt werden? • Wie lassen sich Datenstrukturen parallel effizienter bearbeiten nicht Bestandteil dieser Vorlesung. Informatik 2 - Datenstrukturen
Streams Motivation • Zur Erinnerung: Durchlaufen einer Datenstruktur mit Hilfe von Iteratoren, Beispiel: for (Iterator<String> iter = names.iterator(); iter.hasNext(); ) { System.out.println(iter.next()); } • Beispiel zur Summation aller positiven Werte: int sum = 0; for (Iterator<Integer> iter = values.iterator(); iter.hasNext(); ) { int value = iter.next(); if (value > 0) { sum += iter.next(); } } • Es zeigt sich ein immer wiederkehrendes Muster: • äußere Schleife zum Durchlaufen • innerhalb der Schleife mit dem eigentlichen Code • Problem: Große Datenstrukturen werden immer sequentiell abgearbeitet, obwohl im Computer vielleicht einige Prozessorkerne nichts zu tun haben. • Die Stream-API übernimmt das Durchlaufen der Collection-Klassen und Anwenden der Funktionen auf die einzelnen Elemente. Informatik 2 - Datenstrukturen
StreamsEinführung • Was bietet die Stream-API? • Filtern von Werten (z.B. nur Strings einer bestimmten Länge auswählen) • Abbilden von Daten eins Typs auf andere Typen (z.B. automatisch die Kundennummer aus einem Kundenobjekt auslesen) • Begrenzung der Elemente (z.B. nur die ersten 100 Elemente berücksichtigen) • Sortierung der Elemente beim Auslesen • Reduktions-Operationen wie z.B. Summenbildung, erstes Element mit einer bestimmten Bedingung suchen, … • Und vieles mehr, was aus Zeitgründen hier entfällt. • Die übergebenen Funktionen sind Lambda-Ausdrücke. • Ablauf: • Die Collections-Klassen besitzen eine Methode stream, um einen Stream zu erzeugen. Datenstruktur Funktion1 Funktion2 Funktion3 Ergebnis Informatik 2 - Datenstrukturen