Motivation: Stapel 12. Dynamische Datenstrukturen Verkettete Listen, Abstrakte Datentypen Stapel, Warteschlange, Implementationsvarianten der verketteten Liste 303 Motivation: Stapel ( push, pop, top, empty ) 3 5 1 2 3 5 1 2 push(4) top() → 3 304 Wir brauchen einen neuen Container! Container bisher: Array (T[]) 4 3 5 1 2 pop() 3 5 1 2 3 5 1 2 pop() empty() → false 5 1 2 push(1) 1 5 1 2 Zusammenhängender Speicherbereich, wahlfreier Zugriff (auf i-tes Element) Simulation eines Stapels durch ein Array? Nein, irgendwann ist das Array “voll.” top Ziel: Bau einer Stapel-Klasse! Frage: wie schaffen wir bei push neuen Platz auf dem Stapel? 3 1 5 6 3 8 9 3 3 8 9 Hier kein push(3) möglich! 305 306 Arrays können wirklich nicht alles. . . Arrays können wirklich nicht alles. . . Einfügen oder Löschen von Elementen „in der Mitte” ist aufwändig. 5 1 6 3 8 9 3 3 8 Das Einfügen oder Löschen von Elementen „in der Mitte” ist aufwändig. 9 5 1 6 3 8 Wollen wir hier einfügen, müssen wir alles rechts davon verschieben (falls da überhaupt noch Platz ist!) 8 8 9 3 Der neue Container: Verkettete Liste 6 Referenz 3 8 9 308 Verkettete Liste: Zoom Kein zusammenhängender Speicherbereich und kein wahlfreier Zugriff Jedes Element “kennt” seinen Nachfolger Einfügen und Löschen beliebiger Elemente ist einfach, auch am Anfang der Liste ⇒ Ein Stapel kann als Liste realisiert werden 5 8 Wollen wir hier löschen, müssen wir alles rechts davon verschieben 307 1 3 ListNode 1 key (Typ int) 5 6 null next (Typ ListNode) class ListNode { int key; ListNode next; 8 9 309 } ListNode (int key, ListNode next){ this .key = key; this .next = next; } 310 Stapel = Referenz aufs oberste Element Abstrakte Datentypen Stack 5 1 top_node 6 Ein Stack ist ein abstrakter Datentyp (ADT) mit Operationen null push(x, S): Legt Element x auf den Stapel S . pop(S): Entfernt und liefert oberstes Element von S , oder null. top(S): Liefert oberstes Element von S , oder null. isEmpty(S): Liefert true wenn Stack leer, sonst false. emptyStack(): Liefert einen leeren Stack. public class Stack { private ListNode top_node; public void push (int value) {...} }; 312 311 Implementation Push top xn xn−1 Implementation Pop x1 null top xn xn−1 x1 null x r push(x, S): 1 2 pop(S): Erzeuge neues Listenelement mit x und Referenz auf den Wert von top. Setze top auf den Knotem mit x. 1 2 3 313 Ist top=null, dann gib null zurück Andernfalls merke Referenz p von top in r. Setze top auf p.next und gib r zurück 314 Analyse Queue (Schlange / Warteschlange / Fifo) Queue ist ein ADT mit folgenden Operationen: enqueue(x, Q): fügt x am Ende der Schlange an. dequeue(Q): entfernt x vom Beginn der Schlange und gibt x zurück (null sonst.) head(Q): liefert das Objekt am Beginn der Schlage zurück (null Jede der Operationen push, pop, top und isEmpty auf dem Stack ist in O(1) Schritten ausführbar. sonst.) isEmpty(Q): liefert true wenn Queue leer, sonst false. emptyQueue(): liefert leere Queue zurück. 315 Implementation Queue x1 x2 xn−1 Invarianten! xn null x head x1 2 3 4 x2 xn−1 xn null null tail head tail Mit dieser Implementation gilt enqueue(x, S): 1 316 entweder head = tail = null, oder head = tail 6= null und head.next = null oder head 6= null und tail 6= null und head 6= tail und head.next 6= null. Erzeuge neues Listenelement mit x und Referenz auf null. Wenn tail 6= null , setze tail.next auf den Knoten mit x. Setze tail auf den Knoten mit x. Ist head = null, dann setze head auf tail. 317 318 Implementation Queue x1 Analyse xn−1 x2 head r null xn tail Jede der Operationen enqueue, dequeue, head und isEmpty auf der Queue ist in O(1) Schritten ausführbar. dequeue(S): 1 2 3 4 Merke Referenz von head in r. Wenn r = null, gib r zurück. Setze den Referenz von head auf head.next. Ist nun head = null, dann setze tail auf null. Gib den Wert von r zurück. 319 Implementationsvarianten verketteter Listen 320 Implementationsvarianten verketteter Listen Liste mit Dummy-Elementen (Sentinels). Doppelt verkettete Liste x1 x2 head xn−1 null xn tail x1 head x2 xn−1 xn null tail Vorteil: Weniger Spezialfälle! Variante davon: genauso, dabei Referenz auf ein Element immer einfach indirekt gespeichert. 321 322 Übersicht (A) (B) (C) (D) enqueue insert delete search concat Θ(1) Θ(1) Θ(1) Θ(1) Θ(1) Θ(1) Θ(1) Θ(1) Θ(n) Θ(n) Θ(1) Θ(1) Θ(n) Θ(n) Θ(n) Θ(n) Θ(n) Θ(1) Θ(1) Θ(1) (A) = Einfach verkettet (B) = Einfach verkettet, mit Dummyelement (C) = Einfach verkettet, mit einfach indirekter Elementaddressierung (D) = Doppelt verkettet 323