3.2 Beschränkter Zugriff: Stapel (Stack) und Warteschlangen (Queue)
Im ersten Kapitel lernen wir einige Datenstrukturen kennen, die sich hervorragend eignen, wenn die Daten in einer festen, einfachen Reihenfolge erzeugt, gelesen und entfernt wereden.
Stapel (Stacks)
Ein Stapel ist eine Datenstruktur, der zwei Operationen unterstützt :
push x
: das Element wird auf einen Stapel bereits existierender Elemente "obenauf" gelegt.pop
: das oberste Element des Stapels wird entfernt.
Stack mit Hilfe von Arrays
Stack
sollte
die folgenden zwei Funktionen implementieren:
public String pop(); public void push (String x);
Mit new Stack()
sollte ein leerer Stack erstellt werden.
Hinweis. Speichern Sie Ihre Daten in einem Array der Länge
Stack mit Hilfe von verketteten Listen
Node
mit zwei Variablen:
public class Node { Node next; String content; }
Warteschlangen (Queues)
Eine Warteschlange unterstützt die selben Funktionenpush x
und pop
wie
ein Stack, allerdings verhalten die sich anders. Ein push x
fügt x
am Ende der Schlange ein, und pop
entfernt das erste/vorderste
Element
und gibt es zurück.
Queues mit einem Array und zwei Pointern
Eine Queue können wir ganz simpel als zyklisches Array implementieren. Unsere Datenstruktur besteht aus einem Array der Größestart
und end
,
die die Werte start
zeigt auf
den Anfang der Warteschlange (also ganz vorne), und end-1
ist das letzte Element.
Am Anfang gilt start = end
. Das Array ist als Wrap-Around-Array gedacht, Ihre
Warteschlange
kann also folgende Form haben:
Die Operation pop
würde nun start
auf 7 erhöhen und den Buchstaben
m
zurückgeben; push e
würde in Zelle 1 den Buchstaben e
schreiben und end
auf 2 erhöhen. Die Größe der Queue, also die Anzahl der
belegten Zellen, errechnen wir mittels
Queues als doppelt verkettete Listen
Alternativ zur Array-Lösung können wir Queues auch mit doppelt verketteten Listen realisieren. Da bei derpop
-Operation das älteste Element entfernt wird,
muss dieses "wissen", welches Element nach ihm eingefügt wurde. Wir brauchen also
auch Pointer von "alt" nach "neu".
DoublyLinkedNode
mit drei
inneren Variablen:
public class DoubleLinkedNode { String content; DoublyLinkedNode before; DoublyLinkedNode behind; }
Nehmen Sie meine Datei QueueDLL.java als Vorlage. Zur Erinnerung können Sie sich meine Implementierung einer (einfach) verketteten Liste anschauen: LinkedList.java
Erinnern Sie sich an Elm. Dort hatten wir ja einen Datentyp
type LinkedList = EmptyNode LinkNode String LinkedListso dass wir mit Hilfe des Datenkonstruktors
LinkNode
Werte verknüpfen konnten, also zum Beispiel
LinkNode "M" (LinkNode "o" (LinkNode "n" (LinkNode "t" (LinkNode "a" (LinkNode "g" EmptyNode)))))Nur, dass es in Elm diesen Datentyp bereits gibt:
List a
mit dem Syntaxzucker,
dass wir statt Datenkonstruktor LinkNode
den Konstruktor ::
mit
Infixschreibweise verwenden dürfen, also
"M" :: ("o" :: ("n" :: ("t" :: ("a" :: ("g" :: [])))))beziehungsweise in noch kompakterer Schreibweise
["M", "o", "n", "t", "a", "g"]Aber lassen Sie sich nicht täuschen: trotz der Schreibweise mit
[...]
handelt
es sich hier um eine verkettete Liste, deren Zellen verstreut im Speicher liegen, und nicht
um ein Array mit random access;
eine Funktion getLastElement: List a -< Maybe a
hätte somit
unvermeidlich Laufzeit Queue
implementieren können,
der push x
und pop
in konstanter amortisierter Zeit
unterstützt;
dass heißt, die Laufzeit einer einzelnen pop
-Operation hängt unter Umständen von
der
Länge der Queue ab, eine Folge von Weitere Beispiele: Listen mit Reinschieben
Stellen Sie sich vor, wir wollen unsere aufgereihten Daten durchgehen können und
ohne großen Aufwand der derzeitigen Stelle
Wenn Sie das Prinzip der doppelt verketteten Liste verstanden haben, sollte es für Sie kein großes Problem sein, das in Java zu implementieren. Wie schaut es mit rein funktionalen Sprachen wie Elm aus?
moveLeft
,
moveRight
, currentElement
, writeHere
und insertRight
unterstützt. Die Laufzeit sollte moveLeft, moveRight, insertRight
etc.)