Bausteine Abstrakte Datentypen Arrays Verkettete Listen Datenstrukturen 1 Ferd van Odenhoven Fontys Hogeschool voor Techniek en Logistiek Venlo Software Engineering 22. September 2014 ODE/FHTBM Datenstrukturen 1 22. September 2014 1/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Bausteine Datentyp Elementare Datenstrukturen Organisation der Daten Wahle einer geeignete Datenstruktur Die vorgeschriebene Operationen führen zu Algorithmen unterschiedlicher Effizienz Auswahl von Datenstruktur und effizienz der Algorithmen sind eng verknüpft. Eine Datenstruktur ist nicht immer eine passive Größe Ein Array ist fix, währenddessen eine Liste flexibeler ist. ODE/FHTBM Datenstrukturen 1 22. September 2014 2/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Bausteine Datentyp Was sind elementare Datenstrukturen? Bausteine Einfach strukurierte Datentypen Arrays (Matrizen) Listen Einfach verkettete Listen, darunter: Speicherplatz-Zuweisung für Listen Grundlagen der Listenverarbeitung Doppelt verkettete Liste zirkuläre Liste Skip lists [Zeichenketten] ODE/FHTBM Datenstrukturen 1 22. September 2014 3/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Bausteine Datentyp Bausteine Betrachten Sie die primären Konstrukte auf unterer Ebene für die Speicherung und Verarbeitung in Java Alle Daten, die wir auf einem Computer verarbeiten, werden in einzelne Bits zerlegt. Mit dem Typ können wir spezifizieren, wie man bestimmte Bit-Mengen verwenden kann. Mit Methoden können wir spezifizieren, welche Operationen wir auf den Daten durchführen wollen. Wir benutzen Java-Klassen um die Daten zu beschreiben, die wir verarbeiten, um die Methoden für die Verarbeitung zu definieren, und um Objekte zu erzeugen, die dann die Information enthalten. Unsere Datenstrukturen bestehen aus Objekten und Verweisen auf Objekte. ODE/FHTBM Datenstrukturen 1 22. September 2014 4/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Bausteine Datentyp Bausteine Programmierumgebungen müssen eine eingebaute Unterstützung für grundlegende Bausteine und ihre Beschreibungen bieten: Zahlen und Zeichen. Eingebaute Basisdatentypen: (in Java) Boolesche Werte (boolean) Zeichen (char) 8-bit ganze Zahlen (byte) 16-bit ganze Zahlen (short) 32-bit ganze Zahlen (integer) 64-bit ganze Zahlen (long) 32-bit Gleitkomma-Zahlen (float) 64-bit Gleitkomma-Zahlen (double) ODE/FHTBM Datenstrukturen 1 22. September 2014 5/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Bausteine Datentyp Bausteine In Java werden diese Basisdatentypen primitive Typen genant und heißen: boolean, char, byte, short, int, long, float, double. In generischer Terminologie heißen diese Standardtypen oft integer (ganze Zahlen), floating-point und character: deren Bereich ist begrenzt. Der Typ boolean enthält die logischen Werte true oder false. Gleitkomma-Zahlen sind näherungsweise reelle Zahlen. ODE/FHTBM Datenstrukturen 1 22. September 2014 6/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Bausteine Datentyp Quiz Puzzler: double d = ?; boolean b = (d==d+1); Question: Für welchen Wert(e) von d kann b gleich true sein? ODE/FHTBM Datenstrukturen 1 22. September 2014 7/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Bausteine Datentyp Datentyp (Def. 3.1) Ein Datentyp ist: eine Wertemenge und eine Sammlung von Operationen auf diesen Werten. Operationen sind mit Typen assoziiert (nicht umgekehrt). Wenn wir eine Operation durchführen, müssen wir sicherstellen, dass sowohl die Operanden als auch das Ergebnis den richtigen Typ haben. Java führt implizite (primitive) Typ-Konvertierungen aus; in sonstige Fällen wenden wir Casts (Umwandlungen) an, also explizite Typ-Konvertierungen; beispielsweise ((float) x /N), wenn x und N ganze Zahlen sind. ODE/FHTBM Datenstrukturen 1 22. September 2014 8/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Bausteine Datentyp Datentyp Wo gibt es Datentypen? - ÜBERALL! Viele Operationen, die mit Standarddatentypen assoziiert sind (wie die arithmetischen Operationen), sind in Java eingebaut. Andere Operationen kommen als Methoden vor, die in Standard-Java-Bibliotheken definiert sind; weitere gibt es in den Java-Methoden, die wir in unserem Programm definieren. Beachten Sie: Wenn wir eine einfache Methode in Java definieren, erzeugen wir einen Datentyp. Die durch die Methode implementierte Operation wird für einen solchen Datentypen definiert. Die Datentypen werden durch die Parameter repräsentiert. Daraus folgt, dass jedes Java-Programm ein Datentyp ist, bestehend aus Wertenmengen und denen mit ihnen assozierten Methode. ODE/FHTBM Datenstrukturen 1 22. September 2014 9/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Bausteine Datentyp Zusammenfassung - Java-Programmierung Wir haben vorwiegend einzelne Teile diskutiert, die wie Bausteine auf Basisdatentypen angewendet werden. Oft arbeiten wir mit riesigen Datenmengen und setzen für diesen Zweck Basismethoden ein. Den Begriff Datenstruktur benutzen wir für einen Mechanismus zur Organisation von Information, der bequeme und effiziente Mechanismen für Zugriff und Bearbeitung bietet. Viele wichtige Datenstrukturen basieren auf der einen oder beiden der zwei grundlegenden Herangehensweisen in Arrays: Wir organisieren die Objekte in einer linearen Reihenfolge mit fester Länge. Listen: Wir organisieren die Objekte auf eine Art ohne festgelegte Länge, die besser für die Bearbeitung geeignet sein könnte. ODE/FHTBM Datenstrukturen 1 22. September 2014 10/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Zur Anwendung abstrakter Datentypen (ADTs) Ein ADT definiert ein Typ (Name) und die dazugehörige Methoden Ein ADT legt keine Datenstruktur fest ADT ist das Grundlagende Konzept der objekt-orientierten Programmierung. Ein ADT ist das Java Interface ähnlich, aber enthält auch Konstruktoren. Eine ADT ist in wesen eine API für 1 Typ! ODE/FHTBM Datenstrukturen 1 22. September 2014 11/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Jaa und Abstrakte Datentypen Wie unterstützt Java das Bedürfnis nach ein ADT? Eine Schnittstelle, die die zu verwendenden Methoden deklariert. Die Methoden sind public. Die Schnittstelle kann sowohl public als package-private sein. Eine Implementierung aller Methoden in der Schnittstelle. Ein Client-Programm, das die public Methoden in der public Schnittstelle benutzt, um auf einer höherer Abstraktionsebene arbeiten zu können. Ein Client-Programm-Teil, das die public Methoden in der package private Schnittstelle benutzt. Frage: warum ist ein Konstruktor niemals Teil einer Java Schnittstelle? ODE/FHTBM Datenstrukturen 1 22. September 2014 12/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Zur Anwendung von ADTs Wir müssen die (abstrakten) Objekte definieren, die wir manipulieren wollen, und die Operationen, die wir auf ihnen durchführen wollen. Wir müssen die Daten in einer Datenstruktur repräsentieren und die Operationen implementieren. Wir wollen sicherstellen, dass die Objekte zum Realisieren einer Anwendung leicht anwendbar sind. Wir wollen den Client von der Implementierung trennen und so erreichen, dass viele Clients eine einfache Implementierung nutzen können, ohne dass wir Code ändern müssen. Wir müssen uns der Kosten von Basisoperationen bewusst sein, (siehe 2. Vorlesung). Diese Kosten zu kalkulieren, ist auf abstrakterer Ebene oft einfacher als durch die genaue Betrachtung einer konkreten Implementierung. ODE/FHTBM Datenstrukturen 1 22. September 2014 13/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Abstrakter Datentyp (Definition 4.1) ADT: Definition 4.1 Ein abstrakter Datentyp (ADT) ist ein Datentyp (eine Menge von Werten und eine Sammlung von Operationen auf diesen Werten), auf den nur durch eine Schnittstelle zugegriffen wird. Ein Programm, das einen ADT benutzt, bezeichnen wir als Client, und ein Programm, das den Datentyp spezifiziert, als eine Implementierung. ODE/FHTBM Datenstrukturen 1 22. September 2014 14/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Eine Punkt-Klasse Implementierung class Point { private double x , y ; Point () { x = Math . random (); y = Math . random (); } Point ( double x , double y ) { this . x = x ; this . y = y ; } Weiter auf folgende Folie. ODE/FHTBM Datenstrukturen 1 22. September 2014 15/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Eine Punkt-Klasse Implementierung 2 (Fortsetzung ) double x () { return x ; } double y () { return y ; } double r () { return Math . sqrt ( x * x + y * y ); } double theta () { return Math . atan2 (y , x ); } double distance ( Point p ) { double dx = this . x () - p . x (); double dy = this . y () - p . y (); return Math . sqrt ( dx * dx + dy * dy ); } } ODE/FHTBM Datenstrukturen 1 22. September 2014 16/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Punkt-Klasse Implementierung 3 Erste Implementierung - Was ist wichtig? Diese Klasse enthält 8 Methoden 2 Konstruktoren 2 Zugriffsmethoden, die Werte der Datenfelder zurückgeben, 2 Methoden für die Umwandlung in Polarkoordinaten, 1 Methode für die Berechnung der Entfernung zu einem anderen Punkt, und Die Daten-Repräsentation ist private und direkter Zugriff oder Änderung ist nur durch Methoden der Klasse selber möglich. Die public-Methoden können dagegen durch jeden Client genutzt werden. Wenn wir verhindern, dass Clients direkt auf die Daten-Repräsentation zugreifen, können wir sie ändern! ODE/FHTBM Datenstrukturen 1 22. September 2014 17/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Punkt-Klasse: Zweite Implementierung 1 class Point { private double r , theta ; Point () { double x = Math . random (); double y = Math . random (); this = new Point (x , y ); } Point ( double x , double y ) { r = Math . sqrt ( x * x ; y * y ); theta = Math . atan2 (y , x ); } Weiter auf folgende Folie. ODE/FHTBM Datenstrukturen 1 22. September 2014 18/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Punkt-Klasse: Zweite Implementierung 2 (Fortsetzung ) double r () { return r ; } double theta { return theta ; } double x () { return r * Math . cos ( theta ); } double y () { return r * Math . sin ( theta ); } double distance ( Point p ) { double dx = x () - p . x (); double dy = y () - p . y (); return Math . sqrt ( dx * dx + dy * dy ); } } ODE/FHTBM Datenstrukturen 1 22. September 2014 19/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Wie leiten Sie eine Schnittstelle ab? Eine Schnittstellendefinition leiten Sie von einer Klassendefinition ab durch löschen: aller private Elemente, die Implementierungen der public Methoden sowie die Parameternamen, so dass nur die Signatur der public Methoden übrig bleibt. Wenn Sie das für zwei beliebige Klassen tun, die eine Schnittstelle implementieren, sollte die selbe Schnittstelle dabei herauskommen. ODE/FHTBM Datenstrukturen 1 22. September 2014 20/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Punkt-Klasse ADT ADT Point // ADT interface { Point () Point ( double , double ) double x () double y () double r () double theta () double distance ( Point ) } ODE/FHTBM Datenstrukturen 1 22. September 2014 21/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Point Schnittstelle in Java interface Point // Java interface { // constructors are not allowed ! double x (); double y (); double r (); double theta (); double distance ( Point ); } ODE/FHTBM Datenstrukturen 1 22. September 2014 22/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Welchen Bezug hat die Schnittstelle zu ADTs? Implementierungen der Klasse Datentyp, wie die Implementierungen von Point durch kartesische Koordinaten oder Polarkoordinaten, werden manchmal konkrete Datentypen genannt. Aus unserer ADT Perspektive implementieren die genannten Klassen aber den selben Datentyp - Point - mit unterschiedlichen Daten-Repräsentationen; denn die Klassen bedienen die selben Methoden, die die selben Signaturen haben. ODE/FHTBM Datenstrukturen 1 22. September 2014 23/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Einführung Abstrakte Datentypen (ADTs) Klasse Point Beispiel Zusammenfassung: Schnittstellen und ADTs gelernt? Die Signaturen der Methoden sind in einer Klasse nicht private. Elemente einer Klasse, die nicht Teil ihrer Schnittstelle sind, sind private! Wir untersuchen die Schnittstellen, bevor wir die Implementierungen betrachten! ODE/FHTBM Datenstrukturen 1 22. September 2014 24/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Arrays Beispiel: Das Sieb des Eratosthenes Arrays Arrays Arrays werden benutzt um alle möglichen Objekttypen zu organisieren. Wir können Arrays als primitiven Typ oder Klasse deklarieren, aber danach nicht mehr vom Typ ändern. Arrays definieren eine endliche sequentielle Ordnung der Elemente. Die Elemente in einem Array von n Elemente können über einen Index im Bereich von 0 bis n-1 erreicht werden. Die Zeit die es kostet ein Item zu finden ist unabhängig vom Wert des Index. Notation: Elemente eines Arrays a sind a[0], a[1], a[2], a[3], . . . ODE/FHTBM Datenstrukturen 1 22. September 2014 25/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Arrays Beispiel: Das Sieb des Eratosthenes Arrays Eine der wichtigsten elementaren Datenstrukturen Ein Array ist eine feste Sammlung von Daten des gleichen Typs, die zusammenhängend gespeichert werden und auf die durch einen Index zugegriffen wird. Das i-te Element eines Array wird als a[i] bezeichnet. In Java müssen Sie als Programmierer selbst darauf achten, dass Sie Indizes benutzen, die nicht negativ sind und kleiner als die Größe des Arrays. Arrays hängen auf praktisch allen Rechnern direkt von der Hauptspeichergröße ab. Sie können sich den gesamten Hauptspeicher als Array vorstellen (Speicheradressen entsprechen den Indizes). Wir können davon ausgehen, dass ein Array-Zugriff wie a[i] in einige wenige Maschinenanweisungen übersetzt wird. ODE/FHTBM Datenstrukturen 1 22. September 2014 26/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Arrays Beispiel: Das Sieb des Eratosthenes Beispiel: Das Sieb des Eratosthenes Finde Primzahlen die kleiner als eine gegebene ganze Zahl. Wir nehmen ein boolean Array bei dem alle a[i] auf true gesetzt sind. Wenn i Primzahl ist wird a[i] auf true gesetzt, sonst auf false. Dann fangen wir an beim letzten Priemzahl Index im Bereich vom Beginn des Arrays, worin alle Priemzahlen bekannt sind. Anschließend werden alle Array-Elemente auf false gesetzt, die Indizes entsprechen, die ein Vielfach dieses Primzahl sind. Jede nächsten Durchgang, wenn notwendig, startet beim letztes Priemzahl in die Reihe von bekannte Priemzahlen vom Anfang des Arrays. Begründe die Tatsache das man fertig ist wenn der Index gleich die Wurzel der Länge des Arrays ist. ODE/FHTBM Datenstrukturen 1 22. September 2014 27/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Arrays Beispiel: Das Sieb des Eratosthenes Beispiel: Das Sieb des Eratosthenes Dieser Algorithmus wird oft in unterlegten Graphenstrukturen in Netzen eingesetzt, Siehe das Buch. Es gibt viele effizientere Implementierungen für diese Methode, Siehe das Buch. Dennoch zeigt diese Implementierung, wie wir uns eine Datenstruktur zu nutzen machen können, ein erstes Berechnungsverfahren zu finden. Denken Sie daran es ist immer ein Wechselspiel zwischen Operationen auf Datenstructuren und umgekehrt. ODE/FHTBM Datenstrukturen 1 22. September 2014 28/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Arrays Beispiel: Das Sieb des Eratosthenes Beispiel: Das Sieb des Eratosthenes class Primes { public static void main ( String [] args ) { int N = integer . parseInt ( args [0]); boolean [] a = new boolean [ N ]; for ( int i = 2; i < N ; i ++) a [ i ] = true ; for ( int i = 2; i < N ; i ++) if ( a [ i ] != false ) for ( int j = i , i * j < N ; j ++) a [ i * j ] = false ; for ( int i = 2; i < N ; i ++ ) if ( i > N - 100 ) if ( a [ i ]) System . out . println ( " " + i ); System . out . println (); } } ODE/FHTBM Datenstrukturen 1 22. September 2014 29/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Arrays Beispiel: Das Sieb des Eratosthenes Das Sieb des Eratosthenes Für die Berechnung aller Primzahlen kleiner als 32 werden a[0] und a[1] nicht benutzt (und nicht angezeigt) 0: 1: 2: 3: a: 0: 1: 2: 3: a: ODE/FHTBM 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 T T T T T T T T T T T T T T T T T T T F F F F F F F F F F F T T F T F T F F F 21 22 23 24 25 T T T T T F F F F F F T F F T F T F F F T F T F 26 27 28 29 30 31 T T T T T T F F F F F F F Datenstrukturen 1 T F T 22. September 2014 30/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Verkettete Listen Verkettete Listen Lineare Struktur: jedes Listelement verweist auf das nächste Listelement! Einfache Operationen, wie insert (einfügen) und remove (entfernen) Konventionen zu Listenkopf und –ende in verketteten Listen wichtigste Basisoperationen Einfügen eines Listenelements (List item insertion) Löschen eines Listenelements (List element deletion) Elementare Listenverarbeitung - einige wichtige Operationen List reversal (Listenumkehrung) und list traversal (Traversierung von Listen) List insertion sort (Sortieren durch Einfügen) Klasse zirkuläre Listen Skip Lists Speicherplatz-Zuweisung für Listen (lists can grow, arrays not) ODE/FHTBM Datenstrukturen 1 22. September 2014 31/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Verkettete Liste verglichen mit Array Verkettete Listen und ihre grundlegenden Eigenschaften verglichen mit Arrays und ihren Anwendungen! Wichtig: (Verschiedene Formen des) Zugriffs auf sequenziell organisierte Elemente Traversierung versus Index in Arrays: Objekt refenzierung Operationen: zB. Sortierung von Elementen (oder Items) in beiden Datenstrukturen? Performanz Themen Spezifischer Listentypen: zirkuläre Liste, skip list System- und Implementierungs-spezifische Entscheidungen Konventionen zu Listenkopf und -ende in verketteten Listen: pros & cons Charakteristika der Speicherplatz-Zuweisung ODE/FHTBM Datenstrukturen 1 22. September 2014 32/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Datenstrukturen verkettete Liste & Array Eine Sache soll klar sein: Eine verkettete Liste als Datenstruktur und eine allgemeine verkettet Liste Klasse sind zwei unterschiedliche Sachen! Als Datenstruktur ist eine verkettete Liste kurz und einfach, zum Beispiel gibt es keine getters und setters. Der einzigen Grund für seine Existenz ist das Sie gebraucht wird innerhalb einen Algorithmus. Eine allgemein anwendbare verkettete Liste ist groß (Code), komplex und robust; Sie soll in alle mögliche und unbekannte Umgebungen funktionieren. Vergleichen Sie mal das einfache Array mit der Java ArrayList, die letzte versucht sogar eine Liste zu sein! ODE/FHTBM Datenstrukturen 1 22. September 2014 33/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Einfache Herangehensweise Implementierungen verketteter Listen Stellen Sie sich verkettete Listen als Implementierungen einer Reihe von Element-(oder Item-)Mengen vor die an einem bestimmten Knoten (node) beginnen, dessen Element wir als erstes in der Folge betrachten. Verfolgen Sie seinen Zeiger auf einen anderen Knoten, womit Sie ein Element (oder Item) erreichen, das wir als zweites in der Folge betrachten, und so weiter. ODE/FHTBM Datenstrukturen 1 22. September 2014 34/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste (Eine erste) Definition einer verketteten Liste Def 3.2 Eine verkettete Liste ist eine Menge von Elementen (oder Items), bei der jedes Element (oder Item) Teil eines Knotens ist, der auch einen Zeiger auf einen Knoten enthält. null Item ODE/FHTBM Item Datenstrukturen 1 Item 22. September 2014 35/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Konventionen für den Endknoten in verketteten Listen Einfache Implementierungen von sequenziellen Elementanordnungen, die eine der folgenden Konventionen für den Zeiger im Endknoten einhalten, auch bekannt unter den Namen: Tail-Referenz. Es ist ein Nullzeiger, der auf keinen Knoten zeigt. Er weist auf einen Dummy-Knoten, der kein Element enthält. Er weist zurück auf den ersten Knoten, so dass eine zirkuläre Liste (circular oder cyclic list) entsteht. ODE/FHTBM Datenstrukturen 1 22. September 2014 36/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Konventionen für den Endknoten in verketteten Listen A null Item Item Item B null Item Item dummy C Item ODE/FHTBM Item Datenstrukturen 1 Item 22. September 2014 37/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Erstellen von verlinkbaren Objekten Folgendermaßen benutzen wir Objekte als Knoten und Verweise auf Objekte als Zeiger: class Node { Object item; Node next;} Wir implementieren also die Knoten in verketteten Listen als Objekte vom Typ Node. Node besteht aus einem Element (dessen Typ hier unwichtig ist) und einem Verweis auf einen Knoten. Wir können eine Liste also mit diesem Kode definieren: class Node < Item > { Item item ; Node < Item > next ; Node ( Item v ) { item = v ; next = null ; } } ODE/FHTBM Datenstrukturen 1 22. September 2014 38/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Java - Löschen in einer verketteten Liste Node-Referenz x zeigt zu dem Node der eine next-Referenz hat, die auf den Node zeigt die man lösschen möchte. Um den Knoten nach Knoten x zu löschen, verwenden wir die Anweisungen t = x.next; x.next = t.next; oder einfach x.next = x.next.next; ODE/FHTBM Datenstrukturen 1 22. September 2014 39/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Java - Einfügen in eine verkettete Liste Um Knoten t an der Stelle nach Knoten x einzufügen, verwenden wir diese Anweisungen t.next = x.next; x.next = t; ODE/FHTBM Datenstrukturen 1 22. September 2014 40/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Elementare Listenverarbeitung Verkettete Listen als Datenstrukturen, die einfacher neu zu ordnen sind Statt ArrayIndexOutOfBoundsException müssen wir jetzt die Referenzen in der verkettete Liste überwachen. Weitere Basisoperationen auf Listen list traversal (Traversierung von Listen) hinzufügen und löschen von Elemente list insertion sort (Sortieren durch Einfügen) ODE/FHTBM Datenstrukturen 1 22. September 2014 41/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Elementare Listenverarbeitung Mit verketteten Listen ist es schwierig direkt auf ein Element (oder Item) zuzugreifen, aber die Neuordnung ist einfacher als bei Arrays. In Listen kommt häufig der Fehler vor, dass ein Verweis auf kein einziges Element zeigt oder auf mehr als ein Element (oder Item) zeigt, wobei ein anderes Element verloren geht. Bestimmte Probleme können wir auch durch Verwendung so genannter zirkulärer (circular oder cyclic) Listen vereinfachen. Die wichtigsten Operationen sind das Einfügen oder Löschen eines Elements (oder Items) in der angegebenen Liste und die Traversierung einer Liste. ODE/FHTBM Datenstrukturen 1 22. September 2014 42/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Definition 2 einer verketteten Liste (wie sie oft implementiert wird) Def 3.3 Eine verkettete Liste ist entweder ein Nullzeiger (A), ein Zeiger auf ein Element (B) oder ein Zeiger auf eine verkettete Liste (C). A null null B Item C null Item ODE/FHTBM Datenstrukturen 1 Item 22. September 2014 43/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Liste durchlaufen (im Vergleich zur Array-Verarbeitung) Wir implementieren eine Methode zur Traversierung einer Liste. Wenn x auf den ersten Knoten einer Liste weist, der Endknoten einen Nullzeiger hat und visit eine Methode ist, der wir ein Element als Parameter übergeben können, könnten wir schreiben: for (Node t = x; t != null; t = t.next) visit(t.item); und damit eine Liste traversieren. Diese Schleife (oder die äquivalente while-Form) ist in Listenverarbeitungsprogrammen allgegenwärtig, ebenso wie eine Schleife dieser Art: for (int i = 0; i < N; i++) in Array-verarbeitenden Programmen. ODE/FHTBM Datenstrukturen 1 22. September 2014 44/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste List reversal (Listenumkehrung) static Node reverse ( Node list ) { Node nextTodo , todo = list , revlist = null ; while ( todo != null ) { nextTodo = todo . next ; todo . next = revlist ; revlist = todo ; todo = nextTodo ; } return revlist ; } ODE/FHTBM Datenstrukturen 1 22. September 2014 45/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste List insertion sort: 1 class SortedList { private int size ; // Data structure with private inner class Node . private Node list ; private class Node { int val ; Node next ; Node ( int v , Node t ) { val = v ; next = t ; } } public int size () { return size ; } ODE/FHTBM Datenstrukturen 1 22. September 2014 46/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste List insertion sort: 2 // Contructor initializes data structure public SortedList () { list = new Node (0 , null ); size = 0; } // insert method that keeps the list sorted . public void insert ( int value ) { Node x = list ; while ( x . next != null && x . next . val < value ) { x = x . next ; } x . next = new Node ( value , x . next ); size ++; } } ODE/FHTBM Datenstrukturen 1 22. September 2014 47/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste List insertion sort: 3 Zwei praktische Aufgaben! Implementieren Sie SortedList die Klasse mal wobei ein Array als Datenstruktur wird eingesetzt. Schreiben Sie für die gegeben Implementierung eine Methode mit nachfolgende Signatur: public int[] getValues() wobei die Werte in der gleichen Reihenordnung stehen als in der sortierte Liste. ODE/FHTBM Datenstrukturen 1 22. September 2014 48/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Listenkopf & -ende Konventionen in verketteten Listen circular, never empty (zirkuläre Liste, nie leer) Häufigste Herangehensweise: Verkettete Liste mit Verweis auf den Listenkopf und leerem Ende (Null Tail) Verkettete Liste mit Dummy-Kopf und leerem Ende Verkettete Liste mit Dummy-Kopf und Endknoten ODE/FHTBM Datenstrukturen 1 22. September 2014 49/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Kopf & Ende Konventionen: Zirkuläre Listen Zirkuläre, nie leere Liste erstes Einfügen: head.next = head; t nach x einfügen: (t and x are Node references, t is a new Node) t.next = x.next; x.next = t; nach x löschen: x.next = x.next.next; Schleife durchlaufen: t = head; do {... t = t.next;} while (t !=head); testen, ob ein Element: head.next == head ODE/FHTBM Datenstrukturen 1 22. September 2014 50/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Kopf & Ende Konventionen: null tail Verweis auf Listenkopf, leeres Ende initialisieren: head = null; t nach x einfügen: (t and x are Node references, t is a new Node) if(x == null) { head = t; head.next = null;} else {t.next = x.next; x.next = t;} nach x löschen: t = x.next; x.next = t.next; Schleife durchlaufen: for (t = head; t != null; t = t.next) testen, ob leer: head == null ODE/FHTBM Datenstrukturen 1 22. September 2014 51/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Kopf & Ende Konventionen: dummy head and null tail Dummy-Kopf und Endknoten initialisieren: head = new Node(); head.next = null; t nach x einfügen: (t and x are Node references, t is a new Node) t.next = x.next; x.next = t; nach x löschen: t = x.next; x.next = t.next; Schleifendurchlauf: for (t = head.next; t != null; t = t.next) testen, ob leer: head.next == null ODE/FHTBM Datenstrukturen 1 22. September 2014 52/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Kopf & Ende Konventionen: dummy head and tail Dummy-Kopf und Dummy Endknoten initialisieren: head = new Node(); tail = new Node(); head.next = tail; tail.next = tail; t nach x einfügen: t.next = x.next; x.next = t; nach x löschen: x.next = x.next.next; Schleife: (t and x are Node references, t is a new Node) for (x = head.next; x != tail; x = x.next) testen, ob leer: head.next == tail ODE/FHTBM Datenstrukturen 1 22. September 2014 53/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Verkettete zirkuläre Listen Circular (cyclic linked lists) Das Josephus Problem, siehe auch: Exercise 1.3.37 on page 168 of the book. Direkte Implementierung durch eine zirkuläre Liste Implementierung durch eine generalisierte zirkuläre Liste Vorteile von Implementierungen mit Client-Schnittstelle ODE/FHTBM Datenstrukturen 1 22. September 2014 54/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Josephus Problem 2 1 2 1 9 9 3 3 8 4 8 4 7 5 7 6 6 Beispiel: jede fünfte wird selektiert ODE/FHTBM Datenstrukturen 1 22. September 2014 55/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Josephus Problem 2 2 9 9 3 3 8 4 8 4 7 6 6 Beispiel: jede fünfte wird selektiert ODE/FHTBM Datenstrukturen 1 22. September 2014 56/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Josephus Problem 2 2 9 9 3 8 6 8 6 Beispiel: jede fünfte wird selektiert ODE/FHTBM Datenstrukturen 1 22. September 2014 57/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Josephus Problem 2 2 9 8 8 Beispiel: jede fünfte wird selektiert ODE/FHTBM Datenstrukturen 1 22. September 2014 58/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Josephus Problem Beim Josephus Problem geht es darum, eine Führungsperson auszuwählen. 8 Die Identität der gewählten Person ist eine Funktion von N(= 9) und M(= 5). Im angegebenen Beispiel wird diese Folge von Knoten aussortiert 5 1 7 4 3 6 9 2 ODE/FHTBM Datenstrukturen 1 22. September 2014 59/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Josephus Problem class Josephus { static class Node { int val ; Node next ; Node ( int v ) { val = v ; } } ODE/FHTBM Datenstrukturen 1 22. September 2014 60/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Josephus Problem public static void main ( String [] args ) { int N = integer . parseInt ( args [0]); int M = integer . parseInt ( args [1]); Node t = new Node (1); Node x = t ; for ( int i = 2; i < N ; i ++) x = ( x . next = new Node ( i )); x . next = t ; while ( x != x . next ) { for ( int i = 1; i < M ; i ++) x = x . next ; x . next = x . next . next ; } system . out . println ( " Survivor is " + x . val ); } } ODE/FHTBM Datenstrukturen 1 22. September 2014 61/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Generalisierung – Klasse zirkuläre Listen class CircularList { static class Node { int val ; Node next ; Node ( int v ) { val = v ; } } Node next ( Node x ) { return x . next ; } int val ( Node x ) { return x . val ; } Node insert ( Node x , int v ) { Node t = new Node ( v ); if ( x == null ) t . next = t ; else { t . next = x . next ; x . next = t ; } return t ; } void remove ( Node x ) { x . next = x . next . next ; } } ODE/FHTBM Datenstrukturen 1 22. September 2014 62/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Generalisierung – Klasse zirkuläre Listen Diese Klasse implementiert Basisoperationen auf zirkulären Listen. Sie erlaubt Clients, solche Listen zu bearbeiten und stellt sicher, dass sie das tun können, ohne sich von den Implementierungsdetails abhängig zu machen. Clients können mit insert einen neuen Knoten mit einem gegebenen Wert nach einem angegebenen Knoten in die Liste einfügen und mit remove den Knoten löschen, der einem angegebenen Knoten folgt. Die Zugriffsmethoden next und val liefern den Clients Werte von Feldern; mit ihnen haben wir Freiheit der Implementierung. ODE/FHTBM Datenstrukturen 1 22. September 2014 63/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Josephus Problem mit zirkulären Listen class JosephusY { public static void main ( String [] args ) { int n = Integer . parseInt ( args [0]); int m = Integer . parseInt ( args [1]); CircularList cl = new CircularList (); CircularList . Node x = null ; for ( int i = 1; i <= n ; i ++) x = cl . insert (x , i ); while ( x != cl . next ( x )) { for ( int i = 1 , i < m ; i ++) x = cl . next ( x ); cl . remove ( x ); } System . out . println ( " Survivor is " + cl . val ( x )); } } ODE/FHTBM Datenstrukturen 1 22. September 2014 64/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Josephus Problem: generalisierten zirkulären Liste Dieses Beispiel bietet ein Szenario mit Implementierung einer Client-Schnittstelle für die zirkuläre Liste. Diese Implementierung der zirkulären Liste nutzt die selben Methoden, wir können sie ohne Änderungen am Programm durchführen. Wir identifizieren die wichtigen Operationen für die Berechnung. Wir kapseln sie alle in einer einzigen Klasse, das hat zwei Vorteile: Wir können im Client auf einer höheren Abstraktionsebene arbeiten. Wir prüfen verschiedene konkrete Implementierungen kritischer Operationen und testen ihre Effektivität. ODE/FHTBM Datenstrukturen 1 22. September 2014 65/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Mögliche Erweiterungen: doppelt verkettete Listen Indem wir weitere Zeiger hinzufügen, können wir zusätzlich die Möglichkeit einer Rückwärtsbewegung durch verkettete Listen schaffen. Wir können Operationen unterstützen, mit denen es möglich wird ”das Element vor einem angegebenen Element zu finden”, indem wir eine Liste mit doppelter Verkettung nutzen, in der wir für jeden Knoten zwei Zeiger verwenden: einen (prev) auf das Element davor, und einen weiteren (next) auf das Element danach. ODE/FHTBM Datenstrukturen 1 22. September 2014 66/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Mögliche Erweiterungen: doppelt verkettete Listen 2 Mit Dummy-Knoten oder einer zirkulären Liste können wir sicherstellen, dass x, x.next.prev, und x.prev.next für jeden Knoten in der doppelt verketteten Liste gleich sind. Wir müssen folgende Operationen ändern oder implementieren remove insert after, insert before ODE/FHTBM und in einer doppelt verketteten Liste. Datenstrukturen 1 22. September 2014 67/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Mögliche Erweiterungen: a Node for a skiplist private class Node <K ,V > { K key ; V val ; Node <K ,V > below , above , prev , next ; Node ( K key , V value ) { this . key = key ; this . val = value ; below = null ; above = null ; prev = null ; next = null ; } } ODE/FHTBM Datenstrukturen 1 22. September 2014 68/69 Bausteine Abstrakte Datentypen Arrays Verkettete Listen Konventionen für Endknote Elementare Listenverarbeitung Verkettete zirkuläre Listen Erweiterungen von der einfach verkettete Liste Mögliche Erweiterungen: a skiplist interface public interface SkipList <K ,V > { int getHeight (); int getSize (); void insert ( K key , V value ); boolean isEmpty (); V removeItem ( K key ); V search ( K key ); } ODE/FHTBM Datenstrukturen 1 22. September 2014 69/69