Informatik

Stapel (Stack): LIFO, Operationen und Anwendungen

Stapel (Stack): LIFO, Operationen und Anwendungen
Stapel (Stack): LIFO, Operationen und Anwendungen
Für Quiz, Lückentext, Lernkarten und Fortschritt ist JavaScript nötig. Alle Inhalte und Lösungen bleiben direkt lesbar.

Ein Stapel, auch Stack oder Kellerspeicher, speichert Elemente nach dem LIFO-Prinzip: Das zuletzt abgelegte Element wird zuerst entnommen. Du arbeitest dabei nur am oberen Ende des Stapels.

Deine Lernziele

Hake ab, was du schon kannst — und komm am Ende hierher zurück!

Das LIFO-Prinzip erkennen

Stell dir einen Stapel aus Umzugskisten vor. Eine neue Kiste stellst du oben ab. Willst du eine Kiste entnehmen, erreichst du ebenfalls zuerst die oberste. Eine weiter unten liegende Kiste wird erst zugänglich, nachdem du alle Kisten über ihr entfernt hast.

Definition

LIFO-Prinzip

LIFO bedeutet Last In, First Out: Das zuletzt eingefügte Element verlässt den Stapel als erstes.

Die Wörter „oben“ und „unten“ beschreiben die logische Ordnung. Ein gezeichneter Stack kann nach oben, nach unten oder zur Seite wachsen, ohne dass sich sein Verhalten ändert.

Ein Stack ist ein abstrakter Datentyp: Seine erlaubten Operationen und deren Wirkung werden festgelegt, ohne eine bestimmte technische Implementierung vorzuschreiben. Er kann beispielsweise mit einem Array oder einer verketteten Liste umgesetzt werden.

Merke

Nicht die Zeichnung und nicht die Speicheradresse bestimmen einen Stack, sondern der beschränkte Zugriff am oberen Ende und die LIFO-Reihenfolge.

Teste dich
Frage 1 von 1LeichtWelche Aussage beschreibt das LIFO-Prinzip?
Lösung: Das zuletzt eingefügte Element wird zuerst entnommen. — Bei einem Stack ist nur das obere Ende unmittelbar zugänglich. Deshalb verlässt das jüngste Element den Stack zuerst.
Mit push, pop und peek arbeiten

Drei Operationen bilden den Kern eines Stacks:

  • push(x) legt das Element x oben auf den Stack.
  • pop() liefert das oberste Element und entfernt es.
  • peek() oder top() liefert das oberste Element, entfernt es aber nicht.

Häufig gibt es zusätzlich eine Prüfung wie is_empty(), die feststellt, ob der Stack leer ist.

Beispiel

Ein leerer Stack erhält nacheinander diese Operationen:

  1. push("A") — oben liegt A.
  2. push("B") — oben liegt nun B, darunter A.
  3. push("C") — oben liegt nun C, darunter B und A.
  4. peek() liefert C. Der Stack bleibt unverändert.
  5. pop() liefert und entfernt C.
  6. Ein weiteres pop() liefert und entfernt B.

Am Ende liegt nur noch A im Stack. Die Entnahmereihenfolge C, B, A ist die umgekehrte Reihenfolge des Einfügens.

Gut zu wissen

pop und peek dürfen nicht verwechselt werden: Beide lesen das oberste Element, aber nur pop verändert den Stack.

Teste dich
Frage 1 von 1MittelIm Stack liegen von unten nach oben rot, grün, blau. Was geschieht bei peek() und anschließendem pop()?
Lösung: peek() liefert blau; pop() liefert und entfernt danach blau. — Oben liegt blau. peek() lässt den Zustand unverändert, sodass auch das folgende pop() noch blau erhält.
Operationsfolgen Schritt für Schritt verfolgen

Bei längeren Folgen hilft eine Zustandsliste. Notiere die Elemente stets in derselben Richtung, zum Beispiel von unten nach oben. Ändere nur das obere Ende.

Beispiel

Mit einem leeren Stack wird ein kurzer Text aufgebaut:

  1. push("sein!")
  2. push("dir")
  3. push("mit")
  4. push("Macht")
  5. push("die")
  6. push("Möge")

Von unten nach oben lautet der Stack nun:

sein!, dir, mit, Macht, die, Möge

Drei pop()-Operationen liefern nacheinander Möge, die, Macht. Im Stack bleiben sein!, dir und mit; mit liegt jetzt oben.

So vermeidest du typische Fehler

  1. Markiere eindeutig, welches Ende oben ist.
  2. Führe die Operationen in der angegebenen Reihenfolge aus.
  3. Schreibe bei pop zuerst den Rückgabewert auf und entferne ihn dann aus deinem Zustandsbild.
  4. Verändere den Stack bei peek nicht.
Teste dich
Frage 1 von 2MittelEin leerer Stack erhält push(4), push(7), pop(), push(9). Welches Element liegt danach oben?
Lösung: 9 — Nach den ersten beiden Schritten liegt 7 oben. pop() entfernt 7; anschließend wird 9 auf 4 gelegt.
Frage 2 von 2SchwerDu möchtest die Zeichen eines Wortes in umgekehrter Reihenfolge ausgeben. Welche Vorgehensweise nutzt das Stack-Prinzip passend?
Lösung: Alle Zeichen von links nach rechts mit push speichern und anschließend mit pop ausgeben. — Weil das zuletzt gespeicherte Zeichen zuerst entnommen wird, kehrt eine Folge von push- und anschließenden pop-Operationen die Reihenfolge um.
Anwendungen und Grenzen beurteilen

Ein Stack passt zu Aufgaben, bei denen der jüngste gespeicherte Zustand zuerst wieder gebraucht wird.

Browser und Rücksprünge

Bei einer vereinfachten Zurück-Funktion wird die zuvor besuchte Seite auf einem Stack gespeichert. Beim Zurückgehen wird die zuletzt gespeicherte Seite zuerst wieder aufgerufen.

Auch verschachtelte Unterprogramm- oder Methodenaufrufe folgen diesem Muster. Zu einem Aufruf wird eine Rücksprungadresse gespeichert. Ruft das Unterprogramm ein weiteres Unterprogramm auf, kommt dessen Rücksprungadresse obenauf. Der zuletzt begonnene Aufruf muss zuerst enden, damit die Rückkehrreihenfolge stimmt.

Ausdrücke und verschachtelte Strukturen

Stacks können Operanden und Operatoren bei der Auswertung mathematischer Ausdrücke zwischenspeichern. Ebenso helfen sie dabei, korrekt verschachtelte Strukturen zu prüfen: Eine zuletzt geöffnete Struktur muss zuerst wieder geschlossen werden.

Stack oder Warteschlange?

Eine Warteschlange entnimmt das älteste Element zuerst. Dieses Prinzip heißt FIFO: First In, First Out. Beim Stack wird dagegen das jüngste Element zuerst entnommen.

SituationPassende OrdnungBegründung
Verschachtelte Funktionsaufrufe beendenStack, LIFODer zuletzt begonnene Aufruf endet zuerst.
Personen in Ankunftsreihenfolge bedienenWarteschlange, FIFODie zuerst angekommene Person kommt zuerst an die Reihe.
Eine Zeichenfolge umkehrenStack, LIFODie zuletzt gespeicherten Zeichen erscheinen zuerst.
Teste dich
Frage 1 von 1MittelWelche Situation passt am besten zu einem Stack?
Lösung: Verschachtelte Aufrufe sollen in umgekehrter Aufrufreihenfolge zurückkehren. — Ein Stack passt, wenn der zuletzt gespeicherte Zustand zuerst wieder benötigt wird.
Einen Stack implementieren und Randfälle behandeln

Die abstrakten Operationen bleiben gleich, auch wenn die interne Darstellung wechselt.

Umsetzung mit einem Array

Ein Array kann die Elemente zusammenhängend speichern. Eine Zählvariable gibt an, wie viele Plätze belegt sind. push schreibt an die nächste freie Stelle und erhöht die Zahl der Elemente. pop verringert sie und liefert das zuvor oberste Element.

Ist das Array voll, muss die Implementierung den Stack vergrößern oder den Einfügeversuch eindeutig ablehnen. Bei dynamischer Vergrößerung können einzelne Operationen wegen des Kopierens länger dauern. Bei üblichen Implementierungen besitzen push und pop im Normalfall konstanten Aufwand, also $O(1)$.

Umsetzung mit einer verketteten Liste

Bei einer einfach verketteten Liste verweist top auf den obersten Knoten. Jeder Knoten enthält einen Wert und einen Verweis auf den darunterliegenden Knoten.

Für push(x):

  1. Erzeuge einen neuen Knoten mit dem Wert x.
  2. Lass ihn auf den bisherigen obersten Knoten verweisen.
  3. Setze top auf den neuen Knoten.

Für pop():

  1. Prüfe zuerst, ob top leer ist.
  2. Merke den Wert des obersten Knotens.
  3. Setze top auf dessen Nachfolger.
  4. Liefere den gemerkten Wert.

Diese Reihenfolge behandelt auch einen Stack mit genau einem Element: Dessen Nachfolger ist leer, also wird der Stack nach pop() korrekt leer.

Unterlauf und Überlauf

Ein pop() oder peek() auf einem leeren Stack verursacht einen Stack-Unterlauf, wenn dieser Fall nicht abgefangen wird. Eine Implementierung muss dafür ein eindeutiges Verhalten festlegen, etwa einen Fehler auszulösen oder ausdrücklich einen besonderen Rückgabewert zu verwenden. Ein regulär speicherbarer Wert wie 0 eignet sich nicht ohne zusätzliche Kennzeichnung als Fehlersignal.

Ein Stack-Überlauf entsteht, wenn mehr Speicher benötigt wird, als für den Stack verfügbar ist. Das kann beispielsweise bei sehr tiefer Verschachtelung oder Rekursion geschehen.

Merke

Prüfe den Leerfall, bevor du auf das oberste Element zugreifst. Sonst findet der fehlerhafte Zugriff bereits vor der eigentlichen Fehlerbehandlung statt.

Teste dich
Frage 1 von 2MittelWarum prüft eine sichere pop-Operation zuerst, ob der Stack leer ist?
Lösung: Ohne oberstes Element kann sie weder einen gültigen Wert lesen noch einen Knoten entfernen. — Der Leerfall ist ein Randfall der Stack-Spezifikation. Er muss behandelt werden, bevor auf einen Wert oder Verweis zugegriffen wird.
Frage 2 von 2SchwerBei einer verketteten Implementierung zeigt top auf den einzigen Knoten. Was muss pop() bewirken?
Lösung: Den Wert liefern und top auf den leeren Nachfolger setzen. — Nach dem Entfernen des einzigen Knotens besitzt der Stack kein Element mehr. Deshalb muss top anschließend leer sein.
Karteikasten
Karteikasten

Überlege zuerst selbst und drehe die Karte anschließend zum Prüfen um.

Alles auf einen Blick
Mindmap
  • Stapel
    • Prinzip
      • LIFO: jüngstes Element zuerst
      • Zugriff nur am oberen Ende
    • Operationen
      • push: auflegen
      • pop: liefern und entfernen
      • peek: nur betrachten
    • Implementierung
      • Array mit belegter Größe
      • verkettete Liste mit top-Verweis
    • Anwendungen
      • Rücksprungadressen
      • Browser-Zurücknavigation
      • Ausdrucks- und Verschachtelungsprüfung
    • Randfälle
      • leerer Stack: Unterlauf
      • begrenzter Speicher: Überlauf
Abschluss-Check
Teste dich
Frage 1 von 3LeichtWelche Operation verändert den Stack nicht?
Lösung: peek()peek() liest nur das oberste Element. push und pop verändern den Zustand.
Frage 2 von 3MittelVon unten nach oben liegen A, B, C im Stack. Nach pop() und push("D"): Was liegt oben?
Lösung: Dpop() entfernt zuerst C. Danach legt push("D") das neue Element auf B.
Frage 3 von 3SchwerEin Programm soll Bearbeitungsschritte in genau umgekehrter Reihenfolge rückgängig machen. Warum eignet sich ein Stack?
Lösung: Der zuletzt ausgeführte und gespeicherte Schritt wird durch LIFO zuerst zurückgenommen. — Rückgängigmachen kehrt die zeitliche Reihenfolge um: Der jüngste gespeicherte Zustand wird zuerst entnommen.

Du beherrschst den Kern des Stacks, wenn du bei jeder Operationsfolge zuerst das obere Element bestimmst, peek und pop auseinanderhältst und den Leerfall ausdrücklich prüfst.

Passend dazu