Informatik

Abstrakter Datentyp: ADT einfach erklärt

Abstrakter Datentyp: ADT einfach erklärt
Abstrakter Datentyp: ADT einfach erklärt
Für Quiz, Lückentext, Lernkarten und Fortschritt ist JavaScript nötig. Alle Inhalte und Lösungen bleiben direkt lesbar.

Ein abstrakter Datentyp (ADT) legt fest, welche Werte und Operationen es gibt und wie sich diese Operationen verhalten. Wie die Daten intern gespeichert werden, bleibt verborgen und darf ausgetauscht werden, solange das sichtbare Verhalten gleich bleibt.

Auf dieser Seite lernst du, Signatur und Semantik zu unterscheiden, einen Stack als ADT zu spezifizieren und eine Implementierung von ihrer Schnittstelle zu trennen.

Deine Lernziele

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

Was macht einen Datentyp abstrakt?

Stell dir einen Stack in einem Programm vor. Du darfst Elemente ablegen, das oberste Element ansehen und es entfernen. Ob das Programm dafür ein Array oder verkettete Knoten verwendet, musst du beim Benutzen nicht wissen.

Definition

Abstrakter Datentyp

Ein abstrakter Datentyp beschreibt einen Wertebereich, die zulässigen Operationen und deren Verhalten. Der Zugriff erfolgt ausschließlich über die festgelegte Schnittstelle; die interne Darstellung gehört nicht zur Definition.

Die Trennung beantwortet zwei verschiedene Fragen:

  • Spezifikation: Was dürfen die Operationen, und welches Ergebnis müssen sie liefern?
  • Implementierung: Wie werden Daten gespeichert und Operationen programmiert?
Merke

Beim ADT zählt das beobachtbare Was. Das interne Wie darf wechseln.

Teste dich
Frage 1 von 1LeichtWelche Aussage beschreibt einen abstrakten Datentyp?
Lösung: Er legt Werte, Operationen und deren Verhalten fest, ohne eine bestimmte interne Speicherung vorzuschreiben. — Ein ADT wird durch seine Schnittstelle und Semantik bestimmt. Private Variablen oder verkettete Knoten können Teile einer Implementierung sein.
Signatur und Semantik gehören zusammen

Eine Signatur nennt den Operationsnamen sowie die Typen der Eingaben und des Ergebnisses. Zum Beispiel bedeutet push: ELEMENT × STACK → STACK: Die Operation erhält ein Element und einen Stack und liefert einen Stack.

Die Signatur sagt noch nicht, welches Element später oben liegt. Dafür braucht man die Semantik: Sie beschreibt die Bedeutung einer Operation und die Regeln ihres Zusammenwirkens mit anderen Operationen.

Beispiel

Die Signaturen insert: ELEMENT × CONTAINER → CONTAINER und next: CONTAINER → ELEMENT könnten sowohl zu einem Stack als auch zu einer Queue passen.

Erst die Semantik entscheidet:

  • Beim Stack liefert next das zuletzt eingefügte Element: LIFO.
  • Bei der Queue liefert next das zuerst eingefügte Element: FIFO.

Gleiche Typangaben bedeuten also nicht automatisch gleiches Verhalten.

Teste dich
Frage 1 von 1MittelZwei Container besitzen gleichartige Signaturen für Einfügen und Abfragen. Was brauchst du zusätzlich, um Stack und Queue zu unterscheiden?
Lösung: Regeln darüber, welches eingefügte Element als Nächstes betrachtet oder entfernt wird. — Die Semantik legt die Reihenfolge fest: Stack bedeutet LIFO, Queue bedeutet FIFO.
Einen Stack vollständig spezifizieren

Ein Stack oder Stapel arbeitet nach dem LIFO-Prinzip: Last In, First Out. Das zuletzt eingefügte Element wird zuerst betrachtet oder entfernt.

Eine mögliche Signatur lautet:

  • emptyStack: → STACK erzeugt einen leeren Stack.
  • isEmpty: STACK → BOOL prüft, ob er leer ist.
  • push: ELEMENT × STACK → STACK legt ein Element oben ab.
  • top: STACK → ELEMENT betrachtet das oberste Element.
  • pop: STACK → STACK entfernt das oberste Element und liefert hier den verbleibenden Stack.

Diese Regeln legen das Verhalten fest:

  • isEmpty(emptyStack()) = true
  • isEmpty(push(x, s)) = false
  • top(push(x, s)) = x
  • pop(push(x, s)) = s
Beispiel

Wir beginnen mit s0 = emptyStack().

  1. s1 = push(4, s0): Oben liegt nun 4.
  2. s2 = push(7, s1): Oben liegt nun 7.
  3. top(s2) liefert 7, verändert s2 aber nicht.
  4. pop(s2) liefert nach der hier gewählten Konvention wieder s1.

Der entscheidende Gedanke: Weil 7 zuletzt eingefügt wurde, wird 7 zuerst betrachtet und entfernt.

Teste dich
Frage 1 von 1MittelAuf den leeren Stack werden nacheinander A, B und C gelegt. Welches Element liefert danach top?
Lösung: CC wurde zuletzt eingefügt und liegt deshalb oben. top betrachtet es, ohne den Stack zu verändern.
Randfälle und Konventionen eindeutig festlegen

Eine Spezifikation ist erst brauchbar, wenn sie auch Randfälle klärt. Bei einem leeren Stack können top und pop kein vorhandenes Element bearbeiten. Deshalb muss die Semantik festlegen, ob die Operation einen Fehler meldet oder anders behandelt wird.

In der Spezifikation dieser Seite gelten top(emptyStack()) und pop(emptyStack()) als Fehler. Damit besitzen top und pop die Vorbedingung, dass der Stack nicht leer ist.

Auch der Rückgabewert von pop ist keine universelle Sprachregel. Verschiedene Schnittstellen verwenden unterschiedliche Konventionen:

  • pop liefert den verbleibenden Stack,
  • pop liefert das entfernte Element,
  • oder pop verändert den Stack und liefert keinen Wert.
Gut zu wissen

Diese Varianten dürfen nicht vermischt werden. Signatur und Semantik müssen gemeinsam eindeutig festlegen, welche Konvention gilt.

Teste dich
Frage 1 von 1MittelEine Spezifikation nennt pop: STACK → ELEMENT. Welche Bedeutung passt zu dieser Signatur?
Lösung: pop liefert das entfernte Element. — Der Ergebnistyp ELEMENT zeigt, dass ein Element zurückgegeben wird. Ob der Stack dabei zusätzlich verändert wird, muss die Semantik festlegen.
Warum Implementierungen austauschbar sein können

Eine Implementierung realisiert die Spezifikation mit konkreten Mitteln. Ein Stack kann zum Beispiel intern ein dynamisches Array oder eine verkettete Liste verwenden.

Bei einer arraybasierten Umsetzung kann die Stackspitze am letzten belegten Feld liegen. Bei einer verketteten Umsetzung kann sie der erste Knoten sein. Von außen bleiben dennoch dieselben Operationen sichtbar.

In Java können öffentliche Methoden die Operationen darstellen und private Felder die interne Repräsentation verbergen. Ein Interface kann die Methodensignaturen vorgeben, drückt die vollständige Semantik aber nicht automatisch aus. Vorbedingungen, Wirkungen und Ergebnisse müssen zusätzlich klar beschrieben und von der Implementierung eingehalten werden.

Beispiel

Eine Anwendung führt nur push, top, pop und isEmpty aus. Die Implementierung wird von einem Array auf verkettete Knoten umgestellt.

Wenn jede Operation weiterhin dieselben Ergebnisse, Wirkungen und Fehlerfälle besitzt, muss die Anwendung nicht geändert werden. Ändert sich dagegen etwa der Rückgabewert von pop, wurde nicht nur die Implementierung ausgetauscht, sondern die Schnittstelle oder Semantik verändert.

So prüfst du eine ADT-Spezifikation:

  1. Nenne den Wertebereich und benötigte weitere Typen.
  2. Notiere für jede Operation eine eindeutige Signatur.
  3. Beschreibe die Wirkung und das Zusammenspiel der Operationen.
  4. Lege Vorbedingungen und Randfälle fest.
  5. Prüfe an Operationsfolgen, ob das gewünschte Verhalten eindeutig folgt.
  6. Halte interne Speicherentscheidungen aus der Spezifikation heraus.
Teste dich
Frage 1 von 1SchwerZwei Stack-Klassen verwenden intern unterschiedliche Datenstrukturen. Wann können beide denselben ADT implementieren?
Lösung: Wenn beide die festgelegten Operationen mit derselben sichtbaren Semantik und denselben Randfällen erfüllen. — Ein ADT erlaubt verschiedene Implementierungen. Entscheidend ist, dass Anwendungen über die Schnittstelle dasselbe festgelegte Verhalten beobachten.
Karteikasten
Karteikasten

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

Alles auf einen Blick
Mindmap
  • Abstrakter Datentyp
    • legt Werte und Operationen fest
    • verbindet Signatur mit Semantik
    • beschreibt Vorbedingungen und Randfälle
    • verbirgt die interne Darstellung
    • erlaubt austauschbare Implementierungen
  • Stack als Beispiel
    • push fügt oben ein
    • top betrachtet oben
    • pop entfernt oben
    • LIFO bestimmt die Reihenfolge
Abschluss-Check
Teste dich
Frage 1 von 3LeichtWas gehört zur Signatur einer Operation?
Lösung: Name sowie Eingabe- und Ergebnistypen — Die Signatur beschreibt die typisierte Form einer Operation. Ihre Bedeutung wird erst durch die Semantik festgelegt.
Frage 2 von 3MittelEs gilt top(push(x, s)) = x. Was drückt diese Regel aus?
Lösung: Nach dem Einfügen von x liegt x oben und kann mit top betrachtet werden. — Die Regel verbindet zwei Operationen semantisch: push legt x oben ab, und top liefert genau dieses Element.
Frage 3 von 3SchwerEine neue Stack-Implementierung liefert bei top plötzlich das älteste Element. Ist das nur ein interner Austausch?
Lösung: Nein. Das beobachtbare Verhalten wechselt von LIFO zu FIFO und verletzt damit die Stack-Semantik. — Austauschbar sind Implementierungen nur, solange Signaturen, Semantik, Vorbedingungen und Randfälle erhalten bleiben.

Wenn du jede Operation durch Signatur, Wirkung und Randfälle beschreiben und eine Operationsfolge vorhersagen kannst, hast du die zentrale Idee des ADT verstanden: Spezifikation festlegen, Implementierung offenlassen.

Passend dazu