Kapitel 15: Abstrakte Datentypen … und deren Implementierung in Python Einführung in die Informatik Wintersemester 2007/08 Prof. Bernhard Jung Übersicht Abstrakte Datentypen ADT Stack ADT Queue Verwandte Datentypen Python-Implementierung(en) Python-Implementierung(en) Hauptlernziele: - Beispiele in der Informatik bekannter abstrakter Datentypen kennen lernen - In den Implementierungen wichtige Konzepte objektorientierter Programmierung erkennen und Kenntnisse dazu vertiefen Literatur G. Saake & K.-U. Sattler. Algorithmen und Datenstrukturen. dPunkt Lehrbuch. 2006. Donald Knuth. The Art of Computer Programming, Volume 1: Fundamental Algorithms, Third Edition. Addison-Wesley, 1997. Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 1 Abstrakte Datentypen (ADT) Datentyp … besteht aus einem Wertebereich, d. h. den Werten, die eine Variable von diesem Datentyp annehmen kann, und einer Menge an Operationen Motivation für abstrakte Datentypen Beschreibung von Datenstrukturen unabhängig von ihrer späteren Implementierung in einer Programmiersprache ADT kann das Verständnis von konkreten, d.h. in einer Programmiersprache implementierten Datentypen verbessern Abstrakter Datentyp Spezifikation der Schnittstelle eines Datentyps nach außen, indem Operationen und ihre Funktionalität festgelegt werden Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Eigenschaften von ADTs es kann mehrere konkrete Datentypen zu demselben ADT geben in der Softwaretechnik können ADT z.B. über Module implementiert werden Eigenschaften von ADT-Modulen: Kapselung: Ein ADT-Modul darf nur über seine Schnittstelle benutzt werden Geheimnisprinzip: Die interne Realisierung eines ADT-Moduls ist verborgen diese Eigenschaften sind analog zu Eigenschaften von Klassen in der objektorientierten Programmierung (OOP) Klassen der OOP besitzen darüber hinaus allerdings weitere Eigenschaften (wie Vererbung, Nachrichtenaustausch, Polymorphismus, …) i.a. ADT ≠ Klasse der OOP ADTs können auch mittels OOP-Klassen implementiert werden Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 2 ADT Stack (Stapel, Kellerspeicher) Ein Stack kann eine beliebige Menge von Objekte) aufnehmen und gibt diese, in entgegen gesetzter Reihenfolge zur Aufnahme, wieder zurück Zentrale Operationen push: ein Objekt oben auf Stapel hinzufügen pop: das oberster Objekt wieder entfernen Einfügen und Entfernen geht nur an oberster Stelle Last In – First Out-Prinzip (LIFO) Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Beispiel für Nutzung von Stacks Verarbeitung von Klammerstrukturen Syntaktischer Test, ob Ausdrücke richtig geschachtelt sind Auswertung von vollständig geklammerten Ausdrücken wie z.B. ((2*(3+4))+5) Vorgehen: Klammerausdruck wird symbolweise eingelesen Initialisierung von je 1 Stack für Operatoren und Operanden Öffnende Klammer wird ignoriert Operand oder Operator werden auf jeweiligen Stack geschrieben Bei schließender Klammer wird oberster Operand vom Stack genommen und auf die obersten Operatoren angewendet; Ergebnis wird wieder auf dem Operanden-Stack abgelegt Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 3 ADT Stack (Stapel, Kellerspeicher) Unterstützte Operationen Konstruktor: leeren Stack erzeugen push(Stack,Objekt) ein Objekt wird als oberstes Element dem Stapel zugefügt pop(Stack) top(Stack) isEmpty(Stack) entfernt das oberste Element vom Stack und liefert es zurück liefert das oberste Element ohne dieses zu entfernen liefert True, falls Stack keine Elemente enthält, sonst False Prof. B. Jung TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Implementierung von Stacks Grundidee Stack = Liste, bei welcher nur an einem Ende Objekte eingefügt bzw. wieder entfernt werden können push(5) Mögliche Implementierungen stack stack 1 2 4 Array-basiert: 5 1 2 4 pop() durch verkettete Liste: stack • 1 • 2 • 4 • stack push(5) Prof. B. Jung • pop() null 5 • 1 • Einführung in die Informatik, WS 2007/08 2 • 4 • null TU Bergakademie Freiberg 4 Implementierung von Stack mit Python Liste # Stack implementiert mit Python list class StackImpl1: def __init__(self): self._l = [] Ähnlich Array-Implementierung aber: Python list ≠ Array! def push(self, obj): self._l = [ obj ] + self._l def pop(self): if self.isEmpty(): raise Exception, "empty stack" obj = self._l[0] self._l = self._l[1:] return obj def top(self): return self._l[0] Laufzeit in dieser Implementierung für push & pop jeweils proportional zu n, mit n = Anzahl Objekte auf Stack Bem.: Implementierung wäre noch einfacher möglich gewesen mittels Methoden append() und pop() der Python-Liste def isEmpty(self): len( self._l Einführung ) == 0 in die Informatik, WS 2007/08 Prof. return B. Jung TU Bergakademie Freiberg Implementierung von Stack mit Python Liste (2) Zusätzliche nützliche Methoden # Stack implementiert mit Python list class StackImpl1: __len__() wird durch builtin-Funktion len() aufgerufen … def __len__(self): # Laenge des Stacks return len(self._l) __str__() wird u.a. durch builtin-Funktionen str() und print aufgerufen def __str__(self): # String-Repr. return str(self._l) Beispiele für Polymorphismus Prof. B. Jung >>> >>> >>> >>> 2 >>> [2, >>> 2 >>> [1] s = StackImpl1() s.push(1) s.push(2) len(s) print s 1] s.pop() print s Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 5 Implementierung von Stack mit verketteter Liste class StackImpl2: def __init__(self): self._stackPointer = None def push(self, element): self._stackPointer = Node(element, self._stackPointer) def pop(self): if self.isEmpty(): raise Exception, "empty stack" e = self._stackPointer.element self._stackPointer = self._stackPointer.next return e def top(self): return self._stackPointer.element def isEmpty(self): return self._stackPointer == None # Knoten fuer verkettete Liste class Node: def __init__(self, element, next): self.element = element Prof. B. Jung Einführung in die Informatik, WS 2007/08 self.next = next Laufzeit für push & pop jeweils proportional zu 1, d.h. konstant TU Bergakademie Freiberg Integer-Stack: Stack, der nur Integer aufnehmen kann Implementierung durch Erweiterung einer Stack-Implementierung nur push() muss neu implementiert werden … so dass Hinzufügen anderer Werte als Integer zurückgewiesen wird alle anderen Stack-Operationen stehen per Vererbung zu Verfügung class IntStack(StackImpl1): # Unterklasse von StackImpl1 def push(self, zahl): if type(zahl) != int: raise Exception, "Typfehler: Argument kein int" self._l = [ zahl ] + self._l Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 6 Integer-Stack: Stack, der nur Integer aufnehmen kann >>> >>> >>> >>> [2, >>> 2 >>> s = IntStack() s.push(1) s.push(2) print s 1] s.pop() s.push("hallo") Traceback (most recent call last): File "<pyshell#20>", line 1, in <module> s.push("hallo") File "C:\Dokumente und Einstellungen\Jung\Eigene Dateien\MyPythonPrograms\adt.py", line 86, in push raise Exception, "Typfehler: Argument kein int" Exception: Typfehler: Argument kein int >>> Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg ADT Queue (Warteschlange) Zentrale Operationen enqueue: ein Objekt wird hinten der Warteschlange zugefügt dequeue: das vorderste Objekt wird entnommen First In – First Out-Prinzip (FIFO) Beispiel für Anwendungen Aufträge an langsame Ausgabegeräte wie Drucker Verarbeitung von Mausklicks in graphischen Benutzeroberflächen Pufferung von Daten bei Datenübergabe zwischen asynchronen Prozessen Mögliche Implementierungen (ähnlich Stack) Array-basiert mittels verketteter Liste Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 7 ADT Queue (Warteschlange) Unterstützte Operationen Konstruktor: leere Queue erzeugen enqueue(Queue,Objekt) ein Objekt wird als hinterstes Element der zugefügt dequeue(Queue) front(Queue) isEmpty(Queue) entfernt das vorderste Element der Queue und liefert es zurück liefert das vorderste Element ohne dieses zu entfernen liefert True, falls Queue keine Elemente enthält, sonst False Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Implementierung von Queue mit Python Liste class QueueImpl1: def __init__(self): self._l = [] def enqueue(self, element): self._l.append(element) def dequeue(self): if self.isEmpty(): raise Exception, "empty queue" e = self._l[0] bei dequeue verschieben von self._l = self._l[1:] n-1 Elementen return e Æ Laufzeit proportional zu n, mit n Länge der Queue def front(self): return self._l[0] def isEmpty(self): return len(self._l) == 0 Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 8 Implementierung von Queue mit verketteter Liste class QueueImpl2: def __init__(self): self._frontPointer = None def enqueue(self, element): if self._frontPointer == None: self._frontPointer = Node(element, None) bei enqueue() wird neues Element hinten angehängt return Æ Laufzeit proportional zu n, p = self._frontPointer while p.next != None: mit n Länge der Queue p = p.next p.next = Node(element, None) def dequeue(self): if self.isEmpty(): raise Exception, "empty queue" e = self._frontPointer.element self._frontPointer = self._frontPointer.next return e def front(self): return self._frontPointer.element def isEmpty(self): Einführung in die Informatik, WS 2007/08 return self._frontPointer == None Prof. B. Jung TU Bergakademie Freiberg Weitere Datentypen Priority Queue ähnlich Queue Elemente werden allerdings um eine Prioritätsangabe (Zahl) ergänzt Operationen: add: ein Element (mit Priorität) hinzufügen remove: Element mit höchster Priorität entfernen peek: liefert Element mit höchster Priorität (ohne es zu entfernen) Beispielanwendungen Scheduling von Prozessen Management von Bandbreiten in Netzwerken Implementierung z.B. Datenpakete mit Echtzeit-Anforderungen bevorzugen wie z.B. Telefonie, Live-Streaming basierend auf Array oder verketteter Liste oft mit Sortierung Deque (double ended queue) ähnlich Queue Einfügen und Entfernen von Elementen aber vorne und hinten möglich Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 9