Praktische Informatik
Datentypen und Datenstrukturen: Feld, Liste, Stapel, Warteschlange
Warum die Wahl der Datenstruktur oft mehr über die Laufzeit entscheidet als die Wahl des Algorithmus.
Benötigte Grundlagen
Dieses Vorwissen brauchst du für das Kapitel. Schau kurz nach, wenn dir etwas davon nicht mehr präsent ist, sonst leg direkt los.
Einführung
Zwei Programme verwalten dieselbe Liste von 100 000 Namen. Beide fügen laufend neue ein und löschen andere. Das eine braucht Sekunden, das andere Minuten.
Der Unterschied liegt nicht im , sondern in der Datenstruktur. Wie die im Speicher angeordnet sind, entscheidet darüber, welche Zugriffe billig und welche teuer sind.
In diesem Kapitel geht es um vier Grundstrukturen und um die entscheidende Frage bei jeder: Welche Zugriffe kommen in meinem Programm häufig vor? Die Antwort darauf legt die Wahl fest, und sie legt sie oft eindeutig fest.
Das kannst du nach diesem Kapitel
einfache und strukturierte unterscheiden.
Aufbau und Zugriffskosten von Feld und verketteter Liste vergleichen.
Stapel und Warteschlange über ihre Zugriffsregel beschreiben und Einsatzfälle nennen.
zu einer gegebenen Aufgabe die passende Datenstruktur begründet auswählen.
den Begriff abstrakter Datentyp erläutern (Vertiefung).
Kurz aufgefrischt
Vorausgesetzt werden und einfache aus Variablen, Datentypen und Wertzuweisung sowie die aus Aufwand von Algorithmen.
Neu ist die Frage, wie angeordnet sind und was das kostet.
Einfache und strukturierte Typen
Ein einfacher speichert genau einen Wert: Ganzzahl, Gleitkommazahl, Wahrheitswert, Zeichen.
Ein strukturierter Datentyp fasst mehrere Werte zu einer Einheit zusammen. Zwei Bauarten sind zu unterscheiden:
- Gleichartig: alle Elemente vom selben Typ, angesprochen über einen Index. Das ist das Feld.
- Ungleichartig: verschiedene Typen, angesprochen über Namen. Das ist der Verbund (auch Datensatz), also etwa eine Person mit Name, Alter und Note.
Verbund und Feld lassen sich beliebig verschachteln, und daraus entsteht praktisch jede Datenhaltung: ein Feld von Verbünden ist bereits eine einfache Tabelle.
Das Feld
Ein Feld liegt zusammenhängend im Speicher. Alle Elemente sind gleich groß und stehen direkt hintereinander.
Index: 0 1 2 3 4
Adresse: 1000 1004 1008 1012 1016
Inhalt: [ 7 ][ 3 ][ 9 ][ 1 ][ 5 ]
Daraus folgt unmittelbar der große Vorteil. Die Adresse des Elements mit Index ist
Das ist eine Multiplikation und eine Addition, unabhängig davon, ob das Feld 10 oder 10 Millionen Einträge hat. Zugriff über den Index kostet also .
Ebenso unmittelbar folgt der Nachteil. Soll vorne etwas eingefügt werden, müssen alle nachfolgenden Elemente um einen Platz nach hinten rücken, damit die Zusammenhängigkeit erhalten bleibt. Das kostet . Dasselbe gilt fürs Löschen. Und die Größe steht beim Anlegen fest; wächst der Bedarf, muss ein größeres Feld angelegt und alles umkopiert werden.
Das Feld: Zugriff über den Index
Die Zellen liegen am Stück, und genau daraus folgt beides. Der Vorteil: Um an zu kommen, braucht der Rechner die Zelle nicht zu suchen, sondern rechnet ihre Adresse aus: Startadresse plus Elementgröße. Eine Multiplikation, eine Addition, fertig; ob das Feld fünf Zellen hat oder fünf Millionen, ändert daran nichts. Der Nachteil steht im selben Bild: Die beiden gestrichelten Plätze am Ende sind der Rest der beim Anlegen festgelegten Größe. Ist er aufgebraucht, hilft kein Anbauen. Es muss ein größeres Feld angelegt und alles umkopiert werden. Und wer vorn etwas einfügen will, muss jede Zelle dahinter um einen Platz nach rechts schieben, sonst läge das Feld nicht mehr am Stück.
Die verkettete Liste
Die verkettete Liste dreht beide Eigenschaften um. Jedes Element (Knoten) enthält den Wert und einen Verweis auf den nächsten Knoten. Die Knoten liegen irgendwo im Speicher verstreut.
[ 7 | •]──→[ 3 | •]──→[ 9 | •]──→[ 1 | ⊥]
↑
Ende
Einfügen ist jetzt billig: Man erzeugt einen Knoten und hängt zwei Verweise um. Nichts muss verschoben werden, also , sofern man schon an der richtigen Stelle steht.
Der Preis ist der Zugriff. Es gibt keine Adressformel mehr; um zum -ten Element zu kommen, muss man vom Anfang aus durchhangeln, also .
Die verkettete Liste: Zugriff über die Zeiger
Dieselben Werte, andere Bauart und alle Eigenschaften kehren sich um. Zwischen den Knoten steht jetzt ein Zeiger, und der ist der ganze Unterschied: Die Knoten dürfen irgendwo im Speicher liegen, weil jeder weiß, wo der nächste steht. Einfügen heißt deshalb zwei Zeiger umhängen statt alles zu verschieben, und die Liste wächst, solange Speicher da ist. Der Preis steht ebenso im Bild: Es gibt keine Adressformel mehr. Wer den dritten Wert will, muss vorn anfangen und sich Zeiger für Zeiger vorarbeiten. 🔴 Vergleiche das mit dem Feld darüber und halte fest, dass keine der beiden Bauarten besser ist. Die Frage lautet nie „welche Struktur ist besser?“, sondern „welche Zugriffe kommen in meinem Programm häufig vor?“
Die Gegenüberstellung
| Aufgabe | Feld | verkettete Liste |
|---|---|---|
| Zugriff über Index | ||
| Einfügen vorn | ||
| Einfügen an bekannter Stelle | ||
| Löschen an bekannter Stelle | ||
| Suchen (unsortiert) | ||
| Größe | fest | wächst nach Bedarf |
| Speicher je Element | nur der Wert | Wert und Verweis |
🔴 Es gibt hier keinen Sieger, und genau das ist die Lehre. Die Frage lautet nie „welche Struktur ist besser?", sondern „welche Zugriffe kommen in meinem Programm häufig vor?". Wer viel über den Index zugreift, nimmt ein Feld. Wer viel einfügt und löscht, nimmt eine Liste.
Beachte auch die letzte Zeile: Eine Liste braucht zusätzlichen Speicher für die Verweise. Bei kleinen Elementen kann der Verweis größer sein als der Wert selbst.
Stapel und Warteschlange
Die nächsten beiden Strukturen sind anders gedacht. Sie schreiben nicht die Anordnung im Speicher vor, sondern die Zugriffsregel: Sie erlauben absichtlich weniger als Feld und Liste.
Der Stapel (Stack) arbeitet nach LIFO, also last in, first out. Man legt oben auf und nimmt oben weg.
┌───┐ ← ablegen und entnehmen
│ 9 │
│ 3 │
│ 7 │
└───┘
Wie ein Bücherstapel: Das zuletzt aufgelegte Buch liegt oben und wird zuerst wieder genommen.
Die Warteschlange (Queue) arbeitet nach FIFO, also first in, first out. Man reiht hinten ein und entnimmt vorn.
entnehmen ←── [ 7 ][ 3 ][ 9 ] ←── einreihen
Wie die Schlange an der Kasse: Wer zuerst kam, ist zuerst dran.
Beide bieten nur zwei wesentliche Zugriffe, üblicherweise ablegen und entnehmen, und beide kosten .
Warum baut man etwas, das weniger kann? Weil die Beschränkung genau das Verhalten erzwingt, das gebraucht wird. Wer eine Warteschlange benutzt, kann sich nicht versehentlich vordrängeln; die Reihenfolge ist durch die Struktur garantiert und nicht durch die Sorgfalt des Programmierers. Das ist derselbe Gedanke, aus dem heraus man einen Typ gibt: Man schließt Fehler aus, statt sie zu vermeiden.
Der Stapel: LIFO
Über dem Stapel steht eine einzige Zugriffsstelle, und sie trägt beide Operationen: push und pop, beide oben. Mehr ist an LIFO nicht dran, das Kürzel ist nur der Name für diese eine Bildeigenschaft. Die 7 liegt seit dem Anfang unten und kommt zuletzt wieder heraus; die 9 kam zuletzt dazu und ist als Erste wieder dran. Der Boden ist geschlossen gezeichnet, und auch das ist keine Verzierung: Ein Stapel bietet keinen Zugriff auf sein unteres Ende an. Genau darin liegt sein Nutzen, wer einen Stapel benutzt, kann die Reihenfolge nicht versehentlich umgehen, weil die Struktur es gar nicht zulässt.
Die Warteschlange: FIFO
Dieselben drei Werte, ein einziger Unterschied, und der genügt: Hier stehen zwei Zugriffsstellen, und sie sitzen an entgegengesetzten Enden. Eingereiht wird hinten, entnommen vorn, also kommt die 7 zuerst wieder heraus. Halte die beiden Bilder nebeneinander: Stapel und Warteschlange unterscheiden sich nicht darin, was sie speichern, sondern an wie vielen und welchen Enden sie offen sind. Deshalb kann man beide mit demselben Feld oder derselben Liste bauen; was sie zu Stapel und Warteschlange macht, sind allein die erlaubten Zugriffe.
Wo man ihnen begegnet
Stapel:
- Die Rücktaste in Editoren und Zeichenprogrammen: Der letzte Schritt wird zuerst rückgängig gemacht.
- Der Aufrufstapel eines Programms: Ruft die Funktion auf und die Funktion , so wird zuerst beendet. Genau darauf beruht die .
- Die Prüfung geschachtelter Klammern: Öffnende Klammer ablegen, bei schließender die oberste entnehmen und vergleichen.
Warteschlange:
- Druckaufträge: Wer zuerst gedruckt hat, bekommt sein Blatt zuerst.
- Tastatureingaben: Die Reihenfolge der Tastendrücke muss erhalten bleiben.
- Netzwerkpakete in einem Puffer.
Bemerkenswert an der Klammerprüfung: Der Stapel macht genau das möglich, woran der endliche aus der theoretischen Informatik scheiterte. Der Automat konnte die Verschachtelungstiefe nicht zählen, weil er nur endlich viele hat; der Stapel kann beliebig hoch werden.
Vertiefung: abstrakte Datentypen
Dieser Abschnitt gehört zum erhöhten Anforderungsniveau.
Fällt dir auf, dass bei Stapel und Warteschlange nie stand, wie sie gespeichert sind? Das ist Absicht.
Ein abstrakter ist durch seine Operationen und deren Verhalten festgelegt, nicht durch die Umsetzung. Für den Stapel:
| Operation | Verhalten |
|---|---|
| legt oben auf | |
| liefert das zuletzt abgelegte Element und entfernt es | |
| sagt, ob nichts mehr da ist |
Ein Stapel lässt sich mit einem Feld umsetzen (Index des obersten Elements mitführen) oder mit einer verketteten Liste (immer vorn einfügen und entnehmen). Beide erfüllen dieselben Zusagen.
Der Nutzen dieser Trennung ist groß: Der benutzende muss nur die Operationen kennen. Wechselt man später die Umsetzung, etwa weil die feste Größe des Feldes stört, bleibt alles Übrige unverändert.
🔴 Das ist derselbe Gedanke wie die Kapselung in der objektorientierten Modellierung: außen die zugesagten Operationen, innen die frei wählbare Umsetzung. Der Fachbegriff dafür ist Datenkapselung, und er ist einer der tragenden Gedanken der praktischen Informatik.
Feld oder Liste? Zwei Fälle entscheiden
Fall A: Ein Programm verwaltet die Messwerte eines Sensors der letzten 24 Stunden, ein Wert je Minute, und greift zur Auswertung ständig auf beliebige Zeitpunkte zu. Fall B: Ein Programm verwaltet eine Warteliste, bei der laufend vorne Personen entfernt und in der Mitte eingefügt werden.
- 1
Immer zuerst dieselbe Frage: Welche Zugriffe kommen häufig vor? Nicht: welche Struktur ist schöner.
- 2
Fall A: Zugriffe: Die Anzahl steht fest (), es wird nie eingefügt oder gelöscht, sondern nur gelesen, und zwar über den Zeitpunkt, also über einen Index.
- 3
Fall A: Entscheidung: Feld. Der Index-Zugriff kostet , die feste Größe ist kein Nachteil, weil sie ohnehin bekannt ist, und es entsteht kein Speicherzuschlag für Verweise.
- 4
Fall B: Zugriffe: ständiges Entfernen vorn und Einfügen in der Mitte. Auf einen Index wird nicht zugegriffen; man arbeitet sich ohnehin durch die Liste.
- 5
Fall B: Entscheidung: Verkettete Liste. Beim Feld würde jedes Entfernen vorn alle folgenden Elemente verschieben, also je Vorgang. Bei der Liste sind es zwei umgehängte Verweise.
- 6
Gegenrechnung für Fall B: Bei 10 000 Wartenden und 10 000 Entnahmen kostet das Feld etwa Verschiebungen, die Liste etwa Zeigeroperationen. Vier Größenordnungen Unterschied, allein durch die Wahl der Struktur.
Fall A: Feld, wegen häufigem Index-Zugriff und fester Größe. Fall B: verkettete Liste, wegen häufigem Einfügen und Löschen.
Klammern mit einem Stapel prüfen
Prüfe mit einem Stapel, ob die Klammerung von korrekt ist, und zeige an , wie der Fehler erkannt wird.
- 1
Regel: Öffnende Klammer ablegen. Schließende Klammer: oberste entnehmen und prüfen, ob sie passt. Am Ende muss der Stapel leer sein.
- 2
Durchlauf :
Zeichen Aktion Stapel danach ablegen nichts ablegen nichts entnehmen , passt ablegen nichts entnehmen , passt entnehmen , passt leer - 3
Stapel am Ende leer, alle Paare passten. Klammerung korrekt.
- 4
Durchlauf : Nach und steht auf dem Stapel. Nun kommt ; entnommen wird , und das passt nicht zu . Der Fehler ist erkannt.
- 5
Warum genau ein Stapel? Weil die zuletzt geöffnete Klammer immer zuerst geschlossen werden muss. Das ist wörtlich die LIFO-Regel, und deshalb passt die Struktur ohne jede Anpassung auf das Problem.
- 6
Und warum kein endlicher ? Weil die Schachtelungstiefe unbegrenzt ist; ein Automat mit endlich vielen kann sie nicht mitzählen. Der Stapel kann beliebig hoch werden und genau deshalb, was der Automat nicht kann.
ist korrekt; bei passt die entnommene nicht zur .
Typischer Fehler
„Die verkettete Liste ist besser als das Feld, weil sie beliebig wachsen kann und Einfügen nur kostet."
Beide genannten Vorteile stimmen, und der Schluss ist trotzdem falsch, weil er die Kehrseite verschweigt.
Der Zugriff kostet . Beim Feld liefert eine Adressformel jedes Element sofort. Bei der Liste muss man vom Anfang aus durchhangeln. Wer in einer über die Indizes 0 bis zugreift, kommt bei der Liste auf statt .
Das beim Einfügen gilt nur, wenn man bereits an der Stelle steht. Heißt die Aufgabe „füge an Position 500 ein", muss man erst 500 Knoten durchlaufen; dann ist auch das .
Der Speicherbedarf ist höher. Jeder Knoten trägt einen Verweis mit. Bei einer Liste von einzelnen Zeichen kann der Verweis achtmal so groß sein wie der Wert.
Und ein Punkt, der in Tabellen nie auftaucht: Ein Feld liegt zusammenhängend im Speicher, eine Liste verstreut. Der Zwischenspeicher des Prozessors lädt immer ganze Blöcke; beim Feld sind die nächsten Elemente dadurch schon da, bei der Liste fast nie. In der Praxis ist ein Feld deshalb oft auch dort schneller, wo die Aufwandstabelle Gleichstand ausweist.
Die richtige Haltung ist also nicht „Liste ist besser", sondern: Erst die häufigen Zugriffe bestimmen, dann die Struktur wählen.
Übung 1
leichta) Was unterscheidet einen einfachen von einem strukturierten ? b) Warum kostet der Zugriff auf das -te Element eines Feldes nur ? c) Nenne je zwei Anwendungen für Stapel und Warteschlange.
Tipp anzeigen
Zu b): Wie liegen die Elemente im Speicher?
Lösung anzeigen
a) Ein einfacher Datentyp speichert genau einen Wert, etwa eine Ganzzahl oder einen Wahrheitswert. Ein strukturierter fasst mehrere Werte zu einer Einheit zusammen, entweder gleichartig über einen Index (Feld) oder ungleichartig über Namen (Verbund).
b) Weil die Elemente zusammenhängend und gleich groß im Speicher liegen. Die Adresse lässt sich damit berechnen:
Das ist eine Multiplikation und eine Addition, unabhängig von der Größe des Feldes.
c) Stapel: Rückgängig-Funktion in Editoren; Aufrufstapel bei Funktionsaufrufen (auch: Klammerprüfung). Warteschlange: Druckaufträge; Tastatureingaben (auch: Netzwerkpuffer).
Detaillierte Schritterklärung anzeigen
Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.
✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.
- 1
a) Ein Wert oder mehrere zu einer Einheit zusammengefasst
Ein einfacher Datentyp speichert genau einen Wert, etwa eine Ganzzahl oder einen Wahrheitswert. Ein strukturierter fasst mehrere Werte zu einer Einheit zusammen: entweder gleichartig über einen Index (Feld) oder ungleichartig über Namen (Verbund).
- 2
b) Warum der Feldzugriff O(1) kostet: Die Adresse wird berechnet
Weil die Elemente zusammenhängend und gleich groß im Speicher liegen. Die Adresse lässt sich damit ausrechnen: . Das ist eine Multiplikation und eine Addition, unabhängig von der Größe des Feldes.
- 3
c) Stapel und Warteschlange: je zwei Anwendungen mit ihrer Regel
Stapel (zuletzt hinein, zuerst heraus): die Rückgängig-Funktion in Editoren und der Aufrufstapel bei Funktionsaufrufen; auch die Klammerprüfung. Warteschlange (zuerst hinein, zuerst heraus): Druckaufträge und Tastatureingaben; auch Netzwerkpuffer.
Übung 2
mittela) Ein Programm liest 1 000 000 Messwerte ein und berechnet danach für beliebige Zeitpunkte den Mittelwert über je 60 Werte. Feld oder Liste? Begründe. b) Ein Programm verwaltet die Aufträge einer Werkstatt: Neue kommen hinzu, erledigte fallen aus der Mitte heraus. Feld oder Liste? Begründe. c) Auf einen leeren Stapel wird 3, 7, 2 abgelegt, dann zweimal entnommen, dann 5 abgelegt. Was liegt oben? d) Dieselbe Folge mit einer Warteschlange: Was wird als Nächstes entnommen?
Tipp anzeigen
Zu c) und d): Schreibe den nach jedem Schritt auf.
Lösung anzeigen
a) Feld. Es wird nur gelesen, nie eingefügt oder gelöscht, und der Zugriff erfolgt über den Zeitpunkt, also über einen Index. Genau dafür ist das Feld gebaut: Zugriff . Bei einer Liste müsste man für jeden Mittelwert vom Anfang aus durchhangeln, was bei einer Million Werten aussichtslos ist. Außerdem entfielen eine Million Verweise, was den Speicherbedarf spürbar senkt.
b) Verkettete Liste. Das Herausnehmen aus der Mitte ist der häufige Fall, und beim Feld müssten dafür jedes Mal alle nachfolgenden Elemente aufrücken, also je Vorgang. Bei der Liste genügt das Umhängen zweier Verweise. Auf einen Index wird nicht zugegriffen, der Nachteil der Liste greift hier also nicht.
c) Ablegen 3, 7, 2 ergibt von unten nach oben . Zweimal entnehmen liefert erst 2, dann 7; übrig bleibt . Nach dem Ablegen von 5 liegt 5 oben, darunter 3.
d) Einreihen 3, 7, 2 ergibt die Schlange (3 ist vorn). Zweimal entnehmen liefert erst 3, dann 7; übrig bleibt 2. Nach dem Einreihen von 5 steht die Schlange als . Als Nächstes wird also 2 entnommen.
Detaillierte Schritterklärung anzeigen
Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.
✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.
- 1
Teil a): Erst die Zugriffe auflisten
Man schreibt auf, was das Programm tatsächlich tut: einmal einlesen, danach nur noch lesen, und zwar über einen Zeitpunkt. Einfügen und Löschen kommen gar nicht vor.
Zwischenergebnis
Nur Index-Zugriff, feste Größe.
Genau dann ist das Feld die richtige Wahl. Die feste Größe ist hier kein Nachteil, weil die Anzahl von vornherein feststeht.
- 2
Teil b): Den häufigen Vorgang finden
Häufig ist hier das Entfernen aus der Mitte. Beim Feld kostet das je Vorgang, bei der Liste .
n\ \text{Entnahmen} \cdot O(n) = O(n^2)
Zwischenergebnis
Feld insgesamt, Liste .
- 3
Teil c): Den Stapel Schritt für Schritt mitschreiben
Man notiert den Zustand nach jedem Vorgang, statt ihn im Kopf zu behalten. Beim Stapel wird immer oben abgelegt und oben entnommen.
Zwischenergebnis
; oben liegt 5.
- 4
Teil d): Dieselbe Folge, andere Regel
Bei der Warteschlange wird hinten eingereiht und vorn entnommen. Man schreibt wieder jeden Zustand mit.
Zwischenergebnis
; als Nächstes kommt 2.
Markiere dir in der Notation immer, welches Ende vorn ist. Genau dort entstehen die meisten Verwechslungen.
Übung 3
schwera) Beschreibe, wie sich ein Stapel mit einem Feld umsetzen lässt. Welche Grenze bleibt? b) Beschreibe, wie sich ein Stapel mit einer verketteten Liste umsetzen lässt. c) (Vertiefung) Was ist ein abstrakter , und welchen Vorteil bringt dieser Begriff? d) Warum kann ein Stapel die Klammerprüfung leisten, ein endlicher aber nicht?
Tipp anzeigen
Zu d): Erinnere dich an die Grenze aus dem Kapitel über reguläre Sprachen.
Lösung anzeigen
a) Man legt ein Feld fester Größe an und führt einen Index mit, der auf das oberste Element zeigt (anfangs für „leer").
- ablegen(): um eins erhöhen, dort eintragen.
- entnehmen(): Wert bei zurückgeben, um eins verringern.
- istLeer(): prüfen, ob .
Beide Vorgänge kosten , weil nichts verschoben wird. Grenze: Die Größe des Feldes ist fest, der Stapel kann also überlaufen. Abhilfe wäre, bei Bedarf ein größeres Feld anzulegen und umzukopieren.
b) Man merkt sich einen Verweis auf den obersten Knoten.
- ablegen(): neuen Knoten erzeugen, dessen Verweis auf den bisherigen obersten zeigen lassen, den Kopfverweis auf den neuen Knoten setzen.
- entnehmen(): Wert des obersten Knotens merken, Kopfverweis auf dessen Nachfolger setzen.
Auch das kostet , und der Stapel kann beliebig wachsen. Der Preis ist der Speicher für die Verweise.
c) Ein abstrakter Datentyp ist allein durch seine Operationen und deren zugesagtes Verhalten festgelegt, nicht durch die Umsetzung. Für den Stapel sind das , , mit der LIFO-Zusage.
Vorteil: Der benutzende kennt nur die Operationen. Man kann die Umsetzung später von a) auf b) wechseln, etwa weil die feste Größe stört, ohne eine einzige Zeile des benutzenden Codes zu ändern. Das ist derselbe Gedanke wie die Kapselung in der objektorientierten Modellierung: außen die Zusagen, innen die frei wählbare Umsetzung.
d) Weil die Verschachtelungstiefe unbegrenzt ist. Ein endlicher Automat merkt sich ausschließlich seinen , und davon hat er endlich viele; er kann deshalb nur endlich viele Tiefen unterscheiden. Genau das wurde beim Nachweis gezeigt, dass nicht regulär ist: Ab einer gewissen Länge landen zwei verschieden tiefe Präfixe im selben Zustand und sind danach ununterscheidbar.
Ein Stapel hat diese Grenze nicht, denn er kann beliebig hoch werden. Er ist genau der Speicher, der dem endlichen Automaten fehlt. Ein Automat mit Stapel heißt Kellerautomat und erkennt tatsächlich Sprachen wie . Das erklärt auch, warum Übersetzer für Programmiersprachen mit einem Stapel arbeiten und nicht mit regulären Ausdrücken.
Detaillierte Schritterklärung anzeigen
Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.
✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.
- 1
a) Stapel mit einem Feld: ein Index genügt
Man legt ein Feld fester Größe an und führt einen Index mit, der auf das oberste Element zeigt (anfangs für „leer“). ablegen(): um eins erhöhen, dort eintragen. entnehmen(): Wert bei zurückgeben, um eins verringern. istLeer(): prüfen, ob .
- 2
b) Stapel mit verketteter Liste: ein Verweis genügt
Man merkt sich einen Verweis auf den obersten Knoten. ablegen(): neuen Knoten erzeugen, dessen Verweis auf den bisherigen obersten zeigen lassen, den Kopfverweis auf den neuen Knoten setzen. entnehmen(): Wert des obersten Knotens merken, Kopfverweis auf dessen Nachfolger setzen. Auch das kostet , und der Stapel kann beliebig wachsen.
- 3
c) (Vertiefung) Der abstrakte Datentyp trennt Zusage von Umsetzung
Ein abstrakter Datentyp ist allein durch seine Operationen und deren zugesagtes Verhalten festgelegt, nicht durch die Umsetzung. Für den Stapel sind das , , mit der LIFO-Zusage. Vorteil: Der benutzende Code kennt nur die Operationen. Man kann die Umsetzung später von a) auf b) wechseln, ohne eine einzige Zeile des benutzenden Codes zu ändern.
- 4
d) Warum ein Stapel die Klammerprüfung leistet und ein Automat nicht
Weil die Verschachtelungstiefe unbegrenzt ist. Ein endlicher Automat merkt sich ausschließlich seinen Zustand, und davon hat er endlich viele. Er kann deshalb nur endlich viele Tiefen unterscheiden. Ein Stapel hat diese Grenze nicht: Er kann beliebig hoch werden und ist genau der Speicher, der dem Automaten fehlt.
Zusammenfassung
Einfache speichern einen Wert, strukturierte fassen mehrere zusammen, gleichartig über einen Index im Feld oder ungleichartig über Namen im Verbund. Ein Feld liegt zusammenhängend im Speicher, weshalb sich die Adresse jedes Elements berechnen lässt und der Index-Zugriff kostet; dafür erzwingen Einfügen und Löschen ein Verschieben mit , und die Größe steht fest. Eine verkettete Liste kehrt beides um: Einfügen und Löschen kosten an bekannter Stelle nur zwei umgehängte Verweise, dafür muss man sich zum -ten Element durchhangeln. Einen Sieger gibt es nicht, entscheidend ist allein, welche Zugriffe im Programm häufig vorkommen. Stapel und Warteschlange legen dagegen keine Speicheranordnung fest, sondern eine Zugriffsregel: LIFO beim Stapel, FIFO bei der Warteschlange, beides in . Dass sie absichtlich wenig erlauben, ist ihr Vorteil, denn die Reihenfolge wird durch die Struktur erzwungen statt der Sorgfalt überlassen. Weil ein Stapel beliebig hoch werden kann, leistet er die Klammerprüfung, an der ein endlicher scheitern muss.


