IK_1_Datenstrukturen.fm Seite 29 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Modul 1: Algorithmen und Datenstrukturen „The hardware was the easy part.“ Seymour Cray, Supercomputer Designer, 1925–1996 [W1] Lernziele Algorithmen und Datenstrukturen gehören zu den klassischen Themen der Informatik und sind unerlässlich zur erfolgreichen Analyse, zum Entwurf und zur Implementierung (Umsetzung) eines Software-Systems. Am Anfang stehen dabei typische Lösungsstrategien, Standardalgorithmen und strukturierte Datentypen. Wir lernen die Methoden und Konzepte kennen, die später für eine systematische Entwicklung von Software nötig sind. Lösungsstrategien Standardalgorithmen Datentypen 1 Algorithmen 32 1.1 1.2 1.3 1.4 1.5 Definition: Was ist ein Algorithmus? 32 Beispiele für Algorithmen 32 Eigenschaften eines Algorithmus 33 Vom Problem zum Programm 33 Modellierung 35 29 IK_1_Datenstrukturen.fm Seite 30 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1.6 Modellierungs-Notationen 36 1.6.1 Pseudo-Code-Notation 36 1.6.2 Programmablaufplan (PAP) 38 1.6.3 Struktogramme 40 1.7 Daten- und Funktionsmodellierungsmodelle 43 1.8 Kontrollelemente von Algorithmen 45 1.8.1 1.8.2 1.8.3 1.8.4 Elementare Operation (Verarbeitung) 46 Sequenz (Folge) 46 Auswahl (Selektion) 46 Wiederholung (Schleife) 47 2 Datentypen und Datenstrukturen 48 2.1 2.2 2.3 2.4 Der Begriff Datenstruktur 48 Der Begriff Datentyp 48 Syntaxdiagramme 50 Variable und Konstante 51 2.4.1 Variable 51 2.4.2 Konstante 53 2.5 Idealisierte Datentypen 54 2.6 Konkrete Datentypen 54 2.6.1 Einfache Datentypen 54 2.6.1.1 Ordinale Datentypen 54 2.6.1.2 Datentyp BOOLEAN 55 2.6.1.3 Datentyp INTEGER 55 2.6.1.4 Datentyp CHAR 55 2.6.1.5 Aufzählungstyp 56 2.6.2 Datentyp REAL 56 2.6.3 Strukturierte Datentypen 57 2.6.3.1 Mengen 57 2.6.3.2 Arrays 57 2.6.3.3 Listen 58 2.6.3.4 Matrizen 59 2.6.3.5 Tabellen und Relationen 60 2.6.3.6 Bäume und Graphen 60 2.6.3.7 Files 64 2.6.3.8 Programme 64 2.6.3.9 Objekte, Klassen und Methoden 64 2.7 Abstrakte Datentypen 65 3 Beispielalgorithmen 67 3.1 Sortieralgorithmen 67 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 Bubblesort 67 Selection Sort 68 Quicksort 69 Insertion Sort 69 Shell Sort 70 Heapsort 70 3.2 Suchalgorithmen 71 3.2.1 Lineare Suche 72 3.2.2 Binäre Suche 72 3.2.3 Suche auf einem binären Baum 73 4 Modulkurzzusammenfassung 74 5 Modulanhang 75 5.1 Literatur 75 5.2 5.3 5.4 5.5 5.6 5.7 5.8 30 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 Bücher 75 Artikel 76 Books in English 76 Articles in English 77 Journals 78 Internet-Links 78 Prüfungsfragen 78 Lösungen 79 Übungen 80 Diskussionsfragen 80 Timeline: Algorithmen und Datenstrukturen 80 Glossar 81 IK_1_Datenstrukturen.fm Seite 31 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Algorithmen und Datenstrukturen sind als „einigendes Konzept“ so zentral für die gesamte Informatik, dass sie am Anfang jeder Beschäftigung mit Informatik stehen. Algorithmen und Datenstrukturen gehören nahezu untrennbar zusammen, deshalb tauchen auch überall wo über Algorithmen gesprochen wird, die Begriffe der Datenstrukturen auf. Ein Ziel der Informatik ist Analyse, Entwurf und die Implementierung (Umsetzung, Realisierung, Ausprogrammierung) von Software-Systemen. Die Wirklichkeit wird dabei in Modelle abgebildet. Dazu werden sowohl Algorithmen als auch Daten benötigt (Bild 1.1): Ziel: Analyse, Entwurf und Implementierung eines Software-Systems Algorithmen Daten (Konzepte, Bedeutung, Konstruktion, Korrektheit) (Datentypen, Datenabstraktion, Schnittstellen, Datenstrukturen) Bild 1.1 Algorithmen und Daten stehen zentral Abstraktion (Allgemeine Gesetze, Zusammenhänge, Begriffsbildung, Modellbildung) 31 IK_1_Datenstrukturen.fm Seite 32 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1 Algorithmen 1.1 Definition: Was ist ein Algorithmus? Der Begriff Algorithmus geht etwa auf das Jahr 825 und den Araber ABU DSHAFAR MUHAMMED IBN MUSA AL-KHWARIZIMI zurück. Er schrieb ein Lehrbuch über die Übertragung von Gliedern einer Gleichung von einer zur anderern Seite mit dem Titel: „Kitab al jabr w’almuqabalah“. Daraus leitete sich der Begriff Algebra ab. Aus dem Namen des Autors wurde algorism und daraus Algorithmus (Mehrzahl: Algorithmen). Bild 1.2 Eine Briefmarke aus dem Jahr 1983 ist dem „Namensgeber“ des Algorithmus gewidmet [W2, W3] Ein Algorithmus ist eine Verarbeitungsvorschrift. Nach BALZERT (1999) ist ein Algorithmus eine eindeutige, endliche Beschreibung eines allgemeinen, endlichen Verfahrens zur schrittweisen Ermittlung gesuchter Größen aus gegebenen Größen. Die Beschreibung erfolgt in einem Formalismus mit Hilfe von anderen Algorithmen und letztlich elementaren Algorithmen. Ein Algorithmus muss ausführbar sein. Ein Algorithmus dient zur Lösung allgemeiner Probleme – nicht nur zur Lösung eines speziellen Problems! 1.2 Beispiele für Algorithmen Achtung: Was ist ein Algorithmus und was nicht? Beispiel: Ein bestimmtes Modellflugzeug zu bauen ist ein Prozess. Aber eine allgemeine Anleitung zum Bau von Modellflugzeugen (nicht nur eines bestimmten Flugzeugtyps) ist ein Algorithmus. Es muss streng unterschieden werden zwischen Prozess und Algorithmus (Bild 1.3). Die einzelnen Schritte des Algorithmus können von einer Maschine abgearbeitet werden. In einem Computer-System stellt diese „Maschine“ der Prozessor dar (siehe Band 1, Modul 2). Bild 1.3 Prozesse und Algorithmen 32 IK_1_Datenstrukturen.fm Seite 33 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1.3 Eigenschaften eines Algorithmus Welche Eigenschaften muss ein Verfahren (bzw. Prozess) haben, um als Algorithmus im Sinne der Informatik gelten zu können? Viele Verfahren im Alltag kommen dem Grundgedanken eines Algorithmus schon sehr nahe. Allerdings sind oft die wesentlichen Eigenschaften eines „echten“ Algorithmus noch nicht vorhanden. Damit ein Verfahren als Algorithmus gelten kann, müssen folgende vier Eigenschaften vorhanden sein: • • • • Diskretheit: Der Algorithmus besteht aus einer Folge von Schritten. Determiniertheit: Bei gleichen Startbedingungen (Anfangs- und Randbedingungen) wird stets dasselbe Endergebnis erhalten. Eindeutigkeit: Nach jedem Schritt lässt sich der Algorithmus auf höchstens eine Art fortsetzen. Endlichkeit: Der Algorithmus endet nach endlich vielen Schritten. Oft werden bestimmte Werte bewusst nicht definiert, um den Algorithmus für verschiedene Anwendungsfälle „universell“ anwenden zu können. Diese Werte werden dann als Parameter bezeichnet. 1.4 Vom Problem zum Programm In der Informatik steht am Anfang eine Aufgabenstellung, ein Problem. Die Entwicklung eines allgemeinen Planes (Algorithmus) zur Problemlösung nennen wir Algorithmierung. Algorithmierung Die präzise Formulierung eines Algorithmus in einer für Computersysteme interpretierbaren Sprache (Programmiersprache) heißt Programmierung. Programmierung Vom Problem über den Algorithmus zum Programm kommen wir durch eine analytische Vorgehensweise: Analytisches Vorgehen • • • • • • Problem formulieren, Problemanalyse, Problemabstraktion, Problemspezifikation, Algorithmenentwurf, Nachweis der Korrektheit, Verifikation, Aufwandsanalyse, Programmierung (Implementierung). Die Implementierung (Ausprogrammierung) eines SoftwareSystems ist der letzte (und oft kleinste) Teil einer Entwicklung! 33 IK_1_Datenstrukturen.fm Seite 34 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Das folgende Bild veranschaulicht diesen Prozess: Bild 1.4 Die „reale Welt“ wird in der Sprache der Informatik mit Hilfe der Informationstechnik (siehe Band 1) „abgebildet“ Führen wir nun Menschen (people), Prozessschritte (tasks) und Resultate (deliveries) ein, dann ergibt sich das folgende Bild: Bild 1.5 So wird in der Informatik gearbeitet; dieses streng systematische und strukturierte Vorgehen ist vielen am Anfang fremd ... Wir werden den Softwareentwicklungsprozess im Modul 6: Softwaretechnik & Systementwicklung noch genau besprechen. Hier konzentrieren wir uns auf die theoretischen Grundlagen. 34 IK_1_Datenstrukturen.fm Seite 35 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1.5 Modellierung Ausgehend von der Auffassung der Informatik als die Wissenschaft von der (maschinellen) Informationsverarbeitung liegt ein Schwerpunkt besonders in der Analyse, Entwurf und Konstruktion von Informationssystemen (IS). Da es sich bei den Problemstellungen, die von der Informatik gelöst werden sollen, oft um hochkomplexe Probleme handelt, ist systematisches und analytisches Vorgehen unerlässlich. Eine Möglichkeit ist die Modellierung eines realen Systems (aus dem „real life“) mit Hilfe eines abstrakten Modells. Die eigentliche Problemlösung erfolgt dann in diesem Modell. Das folgende Bild zeigt diesen Vorgang sehr anschaulich: Bild 1.6 Problemlösung durch Modellbildung Modelle können oft sehr abstrakt sein (z.B. mathematische Darstellungen durch Graphen) oder sehr nahe an der Wirklichkeit sein (top-level-view). Letztere sollen Sachverhalte veranschaulichen, um eine Aufgliederung in Teilproblemstellungen zu ermöglichen. Im Software-Engineering (siehe Modul 6) werden meistens drei Modelle unterschieden: • • • Funktionsmodell, Datenmodell und Benutzermodell. 35 IK_1_Datenstrukturen.fm Seite 36 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1.6 Modellierungs-Notationen Algorithmen lassen sich auf verschiedene Weise darstellen (visualisieren, modellieren). Eine Darstellung durch Symbole bzw. vereinbarte Zeichen wird Notation (aus lat. notatio = „Beschreibung“) genannt. Notation = Schreibweise Selbstverständlich kann ein Algorithmus in natürlicher Sprache dargestellt werden. Das kann in einer Aufzählung der Befehle (wie in den Beispielen in den nachfolgenden Kapiteln) erfolgen. Zur Vereinfachung und um die Beschreibung eindeutig zu gestalten kann die sprachliche Beschreibung formalisiert werden, z.B.: WENN „x größer als 0“ DANN „berechne Y“ SONST „tu nichts“. Darstellung (Modellierung) und Beschreibung (Dokumentierung) von Algorithmen gehören zur Programmdokumentation. Eine gute Programmdokumentation ist eine notwendige Voraussetzung zur Entwicklung und vor allem zur Wartung hochwertiger Programme. Einige Möglichkeiten, komplexe Abläufe zu modellieren, sind: • • • • Pseudo-Code-Notation, Programmablaufplan (PAP, Flussdiagramm), Struktogramm und Daten- und Funktionsmodellierungsmodelle (z.B. ERM, SADT, UML). 1.6.1 Pseudo-Code-Notation Pseudo-Code ist eine textuelle und semiformale Darstellung von Kontrollstrukturen (siehe Kapitel 1.8) in Anlehnung an problemorientierte Programmiersprachen (siehe Modul 2). Pseudo-Code stellt unabhängig von der (später) verwendeten Programmiersprache die logische Struktur eines Programms dar. Die drei Hauptelemente von Pseudo-Code, die in ihrer Syntax ursprünglich der Programmiersprache Pascal (siehe Modul 2) entliehen sind, heißen: • • • 36 Sequenz, Wiederholung und Auswahl. IK_1_Datenstrukturen.fm Seite 37 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Eine Sequenz beschreibt eine Abfolge von Programmanweisungen, die in der vorgegebenen Reihenfolge von oben nach unten abgearbeitet werden. Eine Wiederholung ist ein Anweisungsteil, der aufgrund einer eindeutigen Bedingung eine bestimmte Anzahl N durchlaufen wird. Eine Auswahl stellt eine Verzweigung aufgrund einer eindeutigen Bedingung innerhalb des Programmes dar. Je nach dem Ergebnis der Bedingung wird entweder der erste Block oder der zweite Block der Programmanweisungen ausgeführt. Bild 1.7 Drei PseudoCode-Elemente, ursprünglich der Programmiersprache Pascal entlehnt Beispiel: Bild 1.8 Ein Beispiel für eine Modellierung in Pseudo-Code. Das Prinzip dabei ist: „Wenn Bedingung erfüllt, dann tue {Anweisungsblock}, sonst tue {Anweisungsblock}“ Einige Vorteile von Pseudocode: • • • Schnell, einfach und jederzeit anzuwenden. Schrittweise Verfeinerung kann durchgeführt werden. Spezifikationen sind leicht nachvollziehbar. Einige Nachteile von Pseudocode: • • • Es existieren keine expliziten Regeln. Gefahr einer zu frühen Detaillierung. Sehr rasch Verlust der Übersichtlichkeit. Ansätze zur Standardisierung von Pseudocode, siehe z.B. [W4] 37 IK_1_Datenstrukturen.fm Seite 38 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1.6.2 Programmablaufplan (PAP) Mit steigender Komplexität der Anforderungen wird es unmöglich, direkt von der Problemstellung zu einem lauffähigen Programm zu kommen. Zuallererst muss eine logische Struktur in die zu lösende Problemstellung gebracht werden. Ein schon relativ altes und (früher) sehr oft verwendetes Hilfsmittel für die grafische Darstellung von Programmabläufen ist der Programmablaufplan (PAP). Dieser ist auch bekannt als Flussdiagramm (flow chart) oder einfach Ablaufplan. Programmablaufpläne dienen zur Visualisierung von kleineren Problemstellungen und Algorithmen. Die wichtigsten Bausteine eines PAP umfassen: Bild 1.9 Die wichtigsten Bausteine eines Programmablaufplanes (PAP) nach DIN 66 001, um Lösungsansätze verständlich darzustellen Bei der Erstellung eines Programmablaufplanes muss das Problem natürlich schon gelöst sein. Dann können sich die Programmierer bei der Umsetzung (Implementierung) in eine (beliebige) Programmiersprache streng an den Ablaufplan halten und sich vollständig auf programmiertechnische Details konzentrieren. Größere Probleme werden in kleine, voneinander unabhängige Teilschritte zerlegt. 38 IK_1_Datenstrukturen.fm Seite 39 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Vorteile von Programmablaufplänen (vgl. SCANLAN (1989)): • • • Gute grafische Darstellung bei einfachen Problemstellungen. Verschiedene Abstraktionsebenen möglich. Alle wichtigen Kontrollstrukturen sind darstellbar. Nachteile von Programmablaufplänen: • • • Bei komplexen Aufgabenstellungen kommt es zu einer oft nicht mehr zu durchschauenden Programmstruktur. Deshalb werden in der Praxis eher Struktogramme (siehe Kapitel 1.6.3) bevorzugt. Es gibt keine direkten Symbole für Schleifenkonstrukte und Rekursionen. Daher kommt es bei großen Programmen zu Unübersichtlichkeit. Verzweigungen und Zusammenführungen können beliebig miteinander kombiniert werden. Das führt zu unstrukturierten Diagrammen und entspricht einer „GOTO-Spaghetti-Programmierung“. Ein Beispiel für einen Programmflussplan: Bild 1.10 Beispiel für einen typischen PAP Anmerkung: Oft wird der Programmflussplan mit dem Datenflussplan verwechselt. Ein Datenflussplan ist eine grafische Übersicht, die Programme und Daten, die zu einer Gesamtaufgabe gehören, miteinander verbindet. Ein Datenflussplan besitzt ähnliche Symbole wie ein Programmablaufplan, aber zusätzliche Sinnbilder für Daten. 39 IK_1_Datenstrukturen.fm Seite 40 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1.6.3 Struktogramme In Anlehnung an die strukturierte Programmierung (siehe Modul 2) haben Struktogramme als grafisches Hilfsmittel zur Veranschaulichung von Programmabläufen eine große Popularität erlangt. Die Verwendung von Programmablaufplänen (PAP) verführt zu unübersichtlicher, maschinenorientierter Programmierung und zu undisziplinierter Verwendung von Programmsprüngen. Daher wurden von NASSI & SHNEIDERMAN (1973) Struktogramme (Program Structure Diagrams, PSD) entwickelt. In Anlehnung an die Erfinder werden sie daher auch als Nassi-Shneiderman-Diagramme (NSD) bezeichnet. Jede einzelne Aktion wird in einen Strukturblock eingetragen (Bild 1.11). Ein Ziel war es dabei, auch die Aktionssteuerungen von Programmiersprachen in der Programmdokumentation zu berücksichtigen. Elemente der Struktogramme nach NASSI-SHNEIDERMAN: Bild 1.11 Die wichtigsten Elemente nach NassiShneiderman (1973), heute DIN 66 261; vergleiche mit Bild 1.7 40 IK_1_Datenstrukturen.fm Seite 41 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Die Sequenz umfasst eine beliebige Anzahl von Programmanweisungen, die jeweils sequentiell (schrittweise hintereinander) abgearbeitet werden. Die Wiederholung stellt einen Anweisungsblock dar, der aufgrund einer Bedingung eine bestimmte Anzahl von Durchläufen ausführt. Bei dem hier dargestellten Grundtyp wird die Ausführungsbedingung jeweils am Anfang überprüft: Wenn die Bedingung erfüllt ist, dann wird der Anweisungsblock durchlaufen. Sonst wird der nachfolgende Programmabschnitt abgearbeitet. In Bild 1.11 gibt es zwei Modifikationen (Abänderungen zur Grundform): • • Bei der ersten Modifikation wird die Abbruchbedingung am Ende der Wiederholungsschleife abgefragt. WENN diese erfüllt wird, DANN wird die folgende Sequenz bearbeitet, SONST wird sie wiederholt. Die zweite Modifikation stellt eine unendliche Wiederholung („Loop“) dar. Eingangs- und Abbruchbedingung werden nicht explizit abgefragt. Diese Struktur wird dann zum funktionsfähigen Programmbestandteil, wenn innerhalb des zu wiederholenden Blocks mindestens eine so genannte Abbruchbedingung vorgesehen ist, die das Verlassen des Blocks ermöglicht. Die Auswahl beschreibt eine Verzweigung aufgrund einer eindeutigen Bedingung (Grundtyp). Auch hier gibt es zwei Modifikationen: • • Die erste Modifikation beschreibt die Möglichkeit einer mehrfachen Verzweigung, bei der auf jede mögliche Bedingung eine bestimmte Alternative folgt. Bei der zweiten Modifikation werden alle Bedingungen, die nicht explizit aufgeführt sind, durch dieselbe Sequenz weiterverarbeitet – weil sie der einzig verbleibende Pfad ist. Ein Struktogramm ist ausschließlich von oben nach unten zu durchlaufen (top-down), wobei dies auch für einzelne Blöcke gilt. Ein Block darf immer nur durch den Eingang „betreten“ und durch den Ausgang „verlassen“ werden. Die Blöcke können je nach dem zu lösenden Problem beliebig aufeinander folgen oder geschachtelt werden. Die Erstellung von Struktogrammen wird durch Software-Werkzeuge (CASE-Tools) erleichtert, siehe z.B. [W5]. 41 IK_1_Datenstrukturen.fm Seite 42 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Einige Vorteile von Struktogrammen: • • • Struktogramme sind auf verschiedenen Abstraktionsebenen anwendbar und ermöglichen somit eine schrittweise Verfeinerung des Entwurfs. Durch die stark strukturierte grafische Darstellung wird die Entwicklung von Algorithmen zur strukturierten Programmierung gefordert. Struktogramme begünstigen die Zerlegung in hierarchische Blöcke. Einige Nachteile von Struktogrammen: • • • Ähnlich wie das Flussdiagramm wird auch das Struktogramm bei komplexen Prozessen schnell unübersichtlich. Wenn ein geschlossener iterativer Prozess noch als Bedingungsschleife dargestellt werden kann („ändere das Bauteil, bis es alle Anforderungen erfüllt“), dann erweist sich die Darstellung parallel ablaufender verteilter Prozesse als schwierig. Das Struktogramm ist zur Darstellung von Entwicklungsprozessen nur bedingt geeignet. In dem nachfolgenden Beispiel ist der gleiche Algorithmus wie bei der Beschreibung der Programmablaufpläne dargestellt, wobei sehr rasch die Unterschiede zwischen diesen beiden Methoden ersichtlich werden. Bild 1.12 Das Beispiel aus Bild 1.10 nochmal in einem Struktogramm dargestellt 42 IK_1_Datenstrukturen.fm Seite 43 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1.7 Daten- und Funktionsmodellierungsmodelle Wir wollen hier lediglich, ausgehend vom Modellierungskonzept, einige Modellierungsmodelle erwähnen. Diese werden wir dann im Modul 6 „Software-Engineering“ genau besprechen. Das Ziel eines Datenmodells ist, bestimmte Gegebenheiten, wie z.B. die für einen Geschäftsprozess in einem Betrieb notwendigen Informationen, in Datenstrukturen (siehe Kapitel 2) abbilden zu können. Ein Datenmodell beschreibt die grundlegenden Eigenschaften, die für alle Erscheinungen einer bestimmten (fachbezogenen) Sichtweise auf die Wirklichkeit eine einheitliche Abbildung erleichtern. Im Datenmodell werden die grundsätzlichen Strukturen, die Beziehungen und die Eigenschaften, die zugeordnet werden können, festgelegt. Im Modellierungsprozess werden dann für notwendige Erscheinungen der Wirklichkeit im Rahmen der Vorgaben des Datenmodells detaillierte Festlegungen getroffen. Diese Festlegungen enthalten alle Definitionen und Beschreibungen von Inhalt, Struktur und Regeln, die auf Daten über die Erscheinungen der Wirklichkeit angewendet werden können. Je genauer die reale Welt erfasst und im Datenmodell beschrieben wird, umso leichter ist es dann, entsprechende Regeln zur Wahrung der Datenintegrität zu definieren. Für die Datenmodellierung werden folgende Techniken angeboten, die eine computergerechte Umsetzung vereinfachen und unterstützen: • • • • Entity-Relationship-Modell (ERM), Petrinetze (Modell zur Beschreibung von Abläufen), Structured Analysis and Design Technique (SADT) und die Unified Modeling Language (UML). Als Ordnungsvorstellung zur Strukturierung von Daten in einer Datenbank (siehe Modul 3) existieren vier Ansätze: • • • • hierarchisches Datenmodell (ein Datensatz wird mit allen hierarchisch von ihm abhängigen Datensätzen als Einheit betrachtet, 1:n-Beziehung), Netzwerkmodell (ein Datensatz kann eine beliebige Anzahl übergeordneter Datensätze aufweisen, n:m-Beziehungen), relationales Datenmodell (beruht auf der Datenstruktur „Tabelle“) und objektorientiertes Datenmodell. 43 IK_1_Datenstrukturen.fm Seite 44 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Das relationale Datenmodell hat besondere Bedeutung für Datenbanken (Modul 3). Bei diesem Datenmodell stehen als Strukturelemente ausschließlich Relationen zur Verfügung, die sich durch Tabellen darstellen lassen. Die Datensätze bilden die Zeilen, und die Merkmale des Objekts. Die Datenfelder entsprechen den Spalten der Tabelle. Beziehungen zwischen beliebigen Datensätzen werden über gleiche Feldinhalte hergestellt. Der Zugriff auf bestimmte Datensätze wird über die Feldinhalte ermöglicht. Die Benutzer arbeiten nur mit logischen bzw. mit mengenorientierten Abfragen, wobei die physische Speicherung und der Datenzugriff für sie im Hintergrund bleiben. Das folgende Bild gibt eine Übersicht, wo welche Basistechniken eingesetzt werden (Details in Modul 6): Bild 1.13 Verschiedene Basistechniken zur Modellierung und wo diese hauptsächlich verwendet werden 44 IK_1_Datenstrukturen.fm Seite 45 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1.8 Kontrollelemente von Algorithmen Algorithmen werden entwickelt, indem kleinste Elemente (Bausteine) zu größeren (komplexeren) Abläufen zusammengesetzt werden. • • • • • • • • elementare Operation (Verarbeitung) Beispiel: „Schneide Fleisch in kleine Würfel“ Sequenz, Folge bzw. sequentielle Ausführung (ein Prozessor!) Beispiel: „Bringe das Wasser zum Kochen, dann gib das Paket Nudeln hinein, schneide das Fleisch, dann das Gemüse ...“ Wiederholung bzw. Schleife Beispiel: „Rühre die Soße so lange, bis diese fest ist“ Auswahl (Selektion) Beispiel: „Nimm Erbsen oder Dosenfrüchte“ parallele Ausführung (mehrere Prozessoren!) Beispiel: „Ich schneide das Fleisch, du das Gemüse, er stellt inzwischen Wasser auf, sie holt die Gewürze ...“ bedingte Ausführung Beispiel: „Wenn Soße zu dünn, dann füge Mehl hinzu“ Unterprogramm: Die Tätigkeit wird anderswo beschrieben und ist mehrfach benutzbar Beispiel: „Bereite Soße so, wie im Anhang erklärt wird“ Rekursion: Anwendung desselben Algorithmus auf Teilproblem Beispiel: Hol Wasser, Katharina! – Ein Loch ist im Eimer – Stopf es! Womit denn? – Mit Kaugummi! – Der Kaugummi reicht nicht! – Dann nimm mehr Kaugummi! – Der Kaugummi ist zu trocken! – Hol Wasser, Katharina ... Mehr wird nicht gebraucht! Es reichen sogar elementare Operationen + Sequenzen + Wiederholungen, um alles programmieren zu können, was überhaupt programmierbar ist! Oft ist es aber einfach komfortabler, mehr als diese drei Grundelemente zu verwenden. Diese Grundelemente stellen Schemata dar, die eindeutig die Reihenfolge festlegen („kontrollieren“), wie die Anweisungen abgearbeitet werden. Daher werden sie als Kontrollelemente bezeichnet (historisch entstanden aus den imperativen Programmiersprachen, Modul 2, Kapitel 2.5.1.1). Im Folgenden sehen wir uns die wichtigsten an, wobei in den jeweiligen Bildern links das Kontrollelement in einem Flussdiagramm nach DIN 66 001, und rechts das gleiche Kontrollelement als Struktogramm nach NASSI-SHNEIDERMAN (DIN 66 261) dargestellt wird. 45 IK_1_Datenstrukturen.fm Seite 46 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1.8.1 Elementare Operation (Verarbeitung) Das grundlegendste Element ist die Verarbeitung (V). Diese enthält eine Anweisung und wird oft als Prozess oder als Aktion bezeichnet: Bild 1.14 Kontrollelemente „Verarbeitung“; rechts: PAP-Element, links: Struktogrammelement A n w e is u n g V 1.8.2 Sequenz (Folge) Die Sequenz (S), auch als Folge bezeichnet, besteht aus einer Anzahl n von Verarbeitungen (V1 ... Vn), die sequentiell (nacheinander) durchlaufen und abgearbeitet werden. Das Wesentliche dabei ist, dass eine Sequenz nach außen wieder als eine Verarbeitung (also ein Block) dargestellt werden kann: Bild 1.15 Kontrollelemente „Sequenz“ 1.8.3 Auswahl (Selektion) Bei der Auswahl (Selektion) werden Verarbeitungen in Abhängigkeit von einer oder mehreren Bedingungen ausgeführt. Damit ergeben sich drei Möglichkeiten: • • • Bild 1.16 Kontrollelemente „Selektion“; darunter die Darstellung als Struktogramm (bei der einseitigen Auswahl wird einfach der Nein-Kasten leer gelassen) 46 einseitige Auswahl (bedingte Verarbeitung), zweiseitige Auswahl (einfache Alternative), Mehrfachauswahl (mehrfache Alternative). IK_1_Datenstrukturen.fm Seite 47 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 1.8.4 Wiederholung (Schleife) Unterschieden wird zwischen Zählschleife und Bedingungsschleife. Bei den Zählschleifen bestimmt eine Laufvariable (Schleifenzähler), die Anzahl der Schleifendurchläufe (z.B. N = 10). Der Schleifenkopf enthält einen Startund einen Endwert. Beginnend beim Startwert wird der Schleifenzähler in jedem Durchlauf bis zum Endwert um einen festen Wert (Schrittweite) erhöht bzw. erniedrigt. Bei Erreichen des Endwerts wird die Schleife zum letzten Mal durchlaufen. In sehr vielen Programmiersprachen leitet das Schlüsselwort FOR eine Zählschleife ein (siehe Syntaxdiagramm Bild 1.20). Anstelle von Wiederholung wird häufiger die Bezeichnung Schleife (loop) verwendet; aber auch Zyklus oder Iteration werden verwendet Bei Bedingungsschleifen werden im Prinzip drei Arten unterschieden: 1) abweisende Schleife: Wiederholung mit vorangehender Bedingungsprüfung (Bild 1.18 links); 2) nicht abweisende Schleife: Wiederholung mit nachfolgender Bedingungsprüfung (Bild 1.18 rechts) und 3) Endlosschleife: Wiederholung ohne Bedingungsprüfung. Bild 1.17 Bedingungsschleifen; Achtung: Eine While-End-Schleife (Bild mitte) bricht (im Gegensatz zu einer Zählschleife) nicht immer ab, wenn z.B. die Endbedingung nicht korrekt formuliert wird – sie sind daher eine häufige Fehlerquelle! Durch das Kontrollelement Auswahl können Schleifen dargestellt werden: Bild 1.18 Die Gegenüberstellung einer „Schleife S mit Bedingung B am Anfang“ (kopfgesteuert) versus „Schleife mit Bedingung am Ende“ (fußgesteuert); darunter die Darstellung mit Struktogrammen; 47 IK_1_Datenstrukturen.fm Seite 48 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2 Datentypen und Datenstrukturen Daten sind codierte Informationen Die Begriffe Information, Daten, Datentyp, Information usw. wurden in Band 1, Modul 1 eingeführt, definiert und werden hier vorausgesetzt. 2.1 Der Begriff Datenstruktur Der Begriff Datenstruktur (data structure) wird im weiteren Sinne oft gleichbedeutend mit Datentyp verwendet. Im engeren Sinne wird unter Datenstruktur jedoch der Aufbau von (zusammengesetzten) Datentypen aus elementaren Datentypen verstanden. Beispiel: In einer objektorientierten Sprache (siehe Modul 2) sind Datenstrukturen Anordnungen von Objekten, deren Beziehungen untereinander nach bestimmten Gesetzmäßigkeiten aufgebaut sind. So genannte Objektklassen werden zur Datenmodellierung verwendet. Verbindungen zwischen zwei Objekten einer Datenstruktur werden durch besondere Attribute dargestellt, die auf andere Objekte verweisen können (oft auch „Referenzieren“ genannt) – die so genannten Zeiger oder Referenzen. In vielen nichtobjektorientierten Programmiersprachen werden statt der Objektklassen und Objekte einfachere Konstruktoren zur Beschreibung einer Datenstruktur verwendet. Dabei entsprechen den Objekten die so genannten Variablen und den Objektklassen die Datentypen. 2.2 Der Begriff Datentyp Zur Erinnerung: Datentypen (data types) stellen in der Informatik „Zeichensorten“ dar, mit denen bestimmte Algorithmen arbeiten. Daten bzw. Datentypen haben immer nur eine maschineninterne Bedeutung (technische Basiszeichen). Computer können erst durch die Information über den Datentyp die Daten entsprechend verarbeiten. Ein Datentyp ist die Festlegung der Interpretation einer gespeicherten (physikalischen) Bitfolge. Datentypen können zunächst grob eingeteilt werden in (Bild 1.19): • • • idealisierte Datentypen (für den theoretischen Entwurf), konkrete Datentypen (die „klassischen“ Datentypen) und abstrakte Datentypen („abstrahiert“ vom konkreten Programm). Die konkreten Datentypen können aus Grundelementen bestehen (Zahlen, 48 IK_1_Datenstrukturen.fm Seite 49 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen logische Werte, Zeichen) oder zusammengesetzt (strukturiert) sein. Wir untergliedern sie in: • • • einfache Datentypen (Grundelemente aller weiteren Datenstrukturen), strukturierte Datentypen (die so genannten Datenstrukturen), Zeiger-Datentypen (dynamische Datenstrukturen). Das folgende Bild gibt einen Überblick über Datentypen: Bild 1.19 Systematik der Datentypen: Hier kommt klar der Unterschied zwischen Datentypen (konkret, einfach) und Datenstrukturen (wie z.B. Mengen, Arrays usw.) heraus; in Anlehnung an Horn (2001), 245 Der Datentyp legt die Art der gespeicherten Information und deren Auswertungsmöglichkeit fest. Die Festlegung des Datentyps für eine Variable wird Definition, Deklaration oder Vereinbarung genannt und besitzt folgenden Aufbau: <definitionskennzeichnung> <identifikation> <typmerkmal> <definitionsabschluss> Beispiel: In der Programmiersprache Pascal z.B. lautet eine Definition: var Zahl integer. „Zahl“ definiert dabei eine ganzzahlige Größe. Die Definitionskennzeichnung kann in manchen Programmiersprachen auch entfallen. Außerdem kann das Typmerkmal der Identifikation bzw. dem Variablennamen voranstehen. Die Möglichkeit der digitalen Wertedarstellung der Informationen eines Anwendungsbereiches bestimmt wesentlich auch die Anwendbarkeit eines Computers. 49 IK_1_Datenstrukturen.fm Seite 50 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.3 Syntaxdiagramme Ähnlich, wie die Struktur von Algorithmen durch Struktogramme dargestellt werden kann (Kapitel 1.6.3), kann auch der Aufbau einer Datenstruktur bildlich dargestellt werden. Weil die Struktur eines Textes als Syntax bezeichnet wird, sprechen wir hier von Syntaxdiagrammen. Der formale Aufbau einer Sprache, d.h. die Aneinanderreihung von Symbolen, wird als Syntax bezeichnet. Die Bedeutung dieser Aneinanderreihung dagegen ist die Semantik. Die Syntax einer Zählschleife (Kapitel 1.8.4) kann durch Syntaxdiagramme anschaulich beschrieben werden: Bild 1.20 Das Grundprinzip eines Syntaxdiagrammes Die rechteckigen Kästchen stehen im Syntaxdiagramm für Komponenten, deren detaillierter Aufbau offen gelassen oder an anderer Stelle beschrieben ist und auf die wir uns durch deren Namen beziehen können. Die runden Elemente beschreiben anonyme Teile, deren Inhalt an der betreffenden Stelle auftreten muss (Bild 1.21). Insbesondere beschreiben Syntaxdiagramme mit Hilfe grafischer Symbole die Syntax einer Programmiersprache (Modul 2 und Modul 5). Bild 1.21 Die Elemente von Syntaxdiagrammen Flussdiagramme und Struktogramme beschreiben den Ablauf eines Programmes. Syntaxdiagramme beschreiben hingegen den formalen Aufbau einer Datenstruktur und (im Modul 2) den formalen Aufbau (Syntax) einer Programmiersprache. Jedes Syntaxdiagramm hat genau einen Eingang und Ausgang. In der Theoretischen Informatik (Modul 5) werden wir noch die BackusNaur-Form (BNF), benannt nach JOHN BACKUS und PETER NAUR (erstmals zur Beschreibung der Syntax von ALGOL 60 verwendet) kennen lernen. Backus-Naur-Form und Syntaxdiagramm sind die Standardbeschreibungstechniken für nahezu alle Programmiersprachen. 50 IK_1_Datenstrukturen.fm Seite 51 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.4 Variable und Konstante 2.4.1 Variable Eine Variable hat prinzipiell drei Bestandteile: • • • Name, Datentyp und Wert. Eine Variable stellt eine Art „Behälter“ für ihren Wert dar. Im Computer wird (z.B. durch den Compiler) entsprechend dem Datentyp eine bestimmte Speicherplatzreservierung für diesen „Behälter“ ausgeführt. Hardwaretechnisch ist eine Variable also eine Benennung von Speicherwörtern. Die Zuweisung eines Wertes an eine Variable ist eine fundamentale Operation in Computerprogrammen. Eine Variable zeigt eine ähnliche Verhaltensweise wie eine Wandtafel: Sie kann jederzeit gelesen werden (liefert Wert), aber sie kann jederzeit gelöscht und überschrieben werden. Die Zuweisung eines Wertes an eine Variable erfolgt oft durch das Operatorzeichen „=“. Zur Unterscheidung vom Gleichheitszeichen verwenden manche Programmiersprachen auch einen Linkspfeil oder „:=“. Wichtig ist die Unterscheidung zwischen Wertzuweisung und Gleichung im mathematischen Sinn. Die Gleichung X=X+1 macht in der Mathematik wenig Sinn (es existiert keine Lösung). In einer Programmiersprache bedeutet der Ausdruck jedoch „Addiere 1 zum Wert von X und speichere das Ergebnis wieder in X“. Kürzer: „Erhöhe X um 1“. In einem Programm kann auf eine Variable durch Nennung ihres Namens Bezug genommen werden. Ihr Datentyp beschreibt die Struktur und den Wertebereich des Variablenwertes. Nur der Wert der Variablen kann durch Operationen manipuliert werden, die für Variable dieses Datentyps in der Programmiersprache definiert sind. Name und Datentyp einer Variablen werden meistens explizit vor der ersten Benutzung durch eine Deklaration festgelegt. In nahezu allen höheren Programmiersprachen müssen Variable vor ihrer Verwendung deklariert werden. Es wird dabei der Datentyp der Variablen und ein Bezeichner angegeben. 51 IK_1_Datenstrukturen.fm Seite 52 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Beispiele für Variablen-Deklaration: In der Programmiersprache FORTRAN (siehe Modul 2) können Variable explizit deklariert werden, z.B. INTEGER V. Variable der Datentypen INTEGER (ganze Zahl) oder REAL (rationale Zahl als Annäherung zur reellen Zahl) können jedoch auch implizit (bei deren ersten Benutzung) deklariert werden. Der Anfangsbuchstabe des Variablennamens entscheidet darüber, von welchem Typ die Variable ist: Beginnt er mit I, J, K, L, M oder N, so hat die Variable den Typ INTEGER, beginnt er mit einem anderen Buchstaben, so ist die Variable vom Typ REAL, z.B.: IV. Die implizite Deklaration von Variablen ist eine häufige Fehlerquelle: Ein Schreibfehler führt sofort eine neue Variable in das Programm ein. In Pascal (siehe Modul 2) müssen alle Variablen vor der ersten Benutzung deklariert werden. Ein Pascal-Programm besteht daher immer aus einem Deklarationsteil und einem Ausführungsteil (dem so genannten Block). Eine eigene Komponente des Deklarationsteils ist die Variablendeklaration, die mit dem Wort VAR eingeleitet wird. Die Deklaration einer Variablen „Körpergröße“ vom Datentyp REAL und einer Variablen „Personenanzahl“ vom Typ INTEGER hat daher das folgende Aussehen: VAR Körpergröße : REAL; Personenanzahl : INTEGER; Ein letztes Beispiel aus der Programmiersprache C (siehe Modul 2): INT Anzahl, Summe, I, J; float EUR_Betrag; Eine Verallgemeinerung sieht folgendermaßen aus: TYP variable oder TYP v1, v2, ... vn (n > 1) Mehrere Variable können kombiniert werden. Diesem Konstrukt kann ein eigener Namen zugewiesen werden. Bei Variablen des gleichen Typs wird von mehrdimensionalen Variablen bzw. Feldern (Arrays, Kapitel 2.6.3.2) gesprochen. 52 IK_1_Datenstrukturen.fm Seite 53 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.4.2 Konstante Konstante (Literale) sind Datenwerte, die direkt in der Anweisungsfolge eines Programms eingetragen werden können (Standardbezeichnung, z.B. Zahlen). Eine Konstante besteht ebenfalls aus drei Bestandteilen: • • • eindeutig festgelegter Bezeichner (Name), Datentyp und fester Wert aus der Wertemenge des Datentyps. Als Konstante bezeichnet man üblicherweise auch Namen für Datenwerte (frei wählbare Bezeichnung). Durch die eindeutige Vereinbarung von Konstanten-Namen wird ein ganz bestimmter Datenwert mit einem Namen versehen und ist damit jederzeit zugreifbar. Konstante repräsentieren einen bestimmten Wert, der sich zur Ausführungszeit des Algorithmus nicht mehr ändert. Beispiele: Pi = 3,1415 (TYP = REAL); A = 1, B = 100 Minimum = 1, Maximum = 100; Autor = „Andreas Holzinger“ Beispiel: In der Programmiersprache C (siehe Modul 2) findet man z.B. zwei Varianten der Konstantenvereinbarungen: const float Pi = 3,1415 #define Pi 3,1415 Die erste Form entspricht dem ANSI-Standard (siehe Band 1) und ist zu bevorzugen. Die zweite Variante ist älter und definiert ein Makro. Vor der eigentlichen Übersetzung wird im gesamten Text die Zeichenkette „Pi“ einfach durch die Zahl 3,1415 ersetzt. Beispiel: In der Sprache Pascal sieht das Ganze so aus: const pi = 3,1415; Eine Zuweisung pi := ... ist im Gültigkeitsbereich von pi verboten. Eine Konstante ist ein Datenelement, dessen Wert sich bei der Ausführung eines Programms nicht ändert. Eine Variable hingegen ist ein Datenelement, dessen Wert sich während der Ausführung eines Programms ändern kann. 53 IK_1_Datenstrukturen.fm Seite 54 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.5 Idealisierte Datentypen Idealisierte Datentypen (ideal im Gegensatz zu real) sind durch den beschränkten (endlichen) Speicherplatz in Computern nicht darstellbar, sind jedoch für den theoretischen Entwurf von Algorithmen hilfreich. 2.6 Konkrete Datentypen Die konkreten Datentypen werden oft als „die“ Datentypen bezeichnet. Sie unterteilen sich in (siehe nochmals Bild 1.18): • • • einfache Datentypen, strukturierte Datentypen und Zeigerdatentypen. 2.6.1 Einfache Datentypen Einfache Datentypen sind die elementaren Grundbausteine aller weiteren Daten. Sie sind nur als Ganzes manipulierbar und sind nicht weiter zerlegbar. Sie unterteilen sich zunächst in zwei Unterarten: • • ordinale Datentypen und Real-Datentypen. 2.6.1.1 Ordinale Datentypen Zu den ordinalen Datentypen zählen die elementarsten Datentypen: • • • BOOLEAN = boolesche Daten, INTEGER = ganze Zahlen, CHAR = Character, endliche Menge von Zeichen; sowie durch Einschränkung abgeleitete Datentypen: • • Aufzählungsdatentypen (enumeration types) und Teilbereichsdatentypen (subrange types). Ordinale Datentypen besitzen folgende gemeinsame Eigenschaften: Im mathematischen Sinn heißt eine Zuordnung eineindeutig, wenn sie umkehrbar eindeutig (bijektiv) ist 54 • • • • • Die Werte eines ordinalen Typs bilden eine geordnete Menge. Jedem Wert ist eineindeutig eine Ordnungsnummer (Ordinalzahl) zugeordnet. Es gibt einen „kleinsten“ und einen „größten“ Wert. Die Ordinalzahl eines Wertes vom Typ INTEGER ist der Wert selbst. Bei Aufzählungstypen hat das erste Element die Ordinalzahl 0, das nächste 1 usw. IK_1_Datenstrukturen.fm Seite 55 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.6.1.2 Datentyp BOOLEAN Der Datentyp BOOLEAN umfasst nur die Werte TRUE (wahr) und FALSE (falsch). Dieser ist vor allem für die Lösung logischer Probleme und zur Konstruktion von Kontrollstrukturen von Algorithmen von Bedeutung. In vielen Programmiersprachen werden diese Wahrheitswerte intern durch 0 bzw. 1 dargestellt. Dies gilt jedoch nicht generell und sollte deshalb nie vorausgesetzt werden. Meistens stehen folgende logische Operatoren (vgl. mit Band 1, Modul 1) zur Verfügung: • • • • NOT AND OR XOR Negation, Logisches Und, Logisches Oder, Exklusives Oder (Antivalenz). 2.6.1.3 Datentyp INTEGER Der Datentyp INTEGER dient zur Darstellung ganzer Zahlen. Das sind Ziffernfolgen ohne Dezimalpunkt mit oder ohne Vorzeichen. Mögliche INTEGER-Konstante sind z.B. 7, -4, +378, 0, usw. Der Zahlbereich für diesen Datentyp liegt üblicherweise zwischen zwei Konstanten MININT und MAXINT, die von der n-Bit-Zahlendarstellung des Computersystems abhängen, also z.B. bei einem 16-Bit-System von –32768 bis +32767. Bei der Entwicklung mit Pseudocode wird INTEGER verwendet, wenn man sich noch nicht auf einen endgültigen Typ festlegen will. Erst bei der Überführung in Programmiercode wird der Typ endgültig entschieden. Als Operationen sind „+“, „–“, „*“, „div“ (ganzzahlige Division) und „mod“ (Rest bei ganzzahliger Division) zulässig. 2.6.1.4 Datentyp CHAR Der Typ CHARACTER (kurz: CHAR) ist in vielen Programmiersprachen ein vordefinierter Datentyp, dessen Wertebereich eine endliche, geordnete Menge von Zeichen (characters) ist. Dazu gehören (mindestens) die Großbuchstaben A bis Z, die Ziffern 0 bis 9 und das Leerzeichen (blank). Elemente des Typs CHAR werden meistens in Apostrophe (’) bzw. in Anführungszeichen (’’) eingeschlossen. Beispiel: ’A’, ’’a’’, ’’.’’, ’$’ usw. 55 IK_1_Datenstrukturen.fm Seite 56 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.6.1.5 Aufzählungstyp Aufzählungstypen können von den Programmierern selbst definiert werden. Die allgemeine Definition eines Aufzählungstyps lautet: type T = (t1, t2, ... tn) T Bezeichner des Typs, t1 ... tn mögliche Werte. Mögliche Operationen auf T sind die Vergleichsoperationen (=, ≠ , <, >, usw.) sowie eine Nachfolgeroperation succ (sucessor) und Vorgängerfunktion pred (predecessor). Beispiel: type farbe = (rot, gruen, blau) rot < gruen < blau 2.6.2 Datentyp REAL Der Datentyp REAL dient zur Darstellung von reellen Zahlen. Das sind Ziffernfolgen mit Dezimalpunkt, mit oder ohne Vorzeichen sowie mit oder ohne Exponent. Mögliche REAL-Konstante sind z.B. –2,7; 36,81; 0,23623E+2 usw. Der Buchstabe E bedeutet dabei ,,mal 10 hoch“. Der Zahlbereich ist naturgemäß wesentlich größer als beim Typ INTEGER. Bei der Entwicklung in Pseudocode wird der Typ REAL verwendet, wenn feststeht, dass eine Maschinennäherung reeller Zahlen benötigt wird, die endgültige Implementierung aber noch nicht festgelegt wird. Variablen vom Typ REAL können als Wert prinzipiell reelle Zahlen annehmen. Da Computersysteme allerdings nur eine beschränkte Speicherkapazität haben, wird der Wertebereich auf Zahlen in Gleitpunktdarstellung eingeschränkt! Gleitpunktdarstellung (floating point) ist eine Methode zur näherungsweisen Darstellung von reellen Zahlen in Computersystemen (siehe Band 1). Für den Datentyp REAL sind die mathematischen Grundoperationen und mathematische Funktionen (Sinus, Logartithmus usw.) möglich. 56 IK_1_Datenstrukturen.fm Seite 57 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.6.3 Strukturierte Datentypen In der Praxis kommt man mit den einfachen Datentypen nicht aus. Daher können in vielen Programmiersprachen beliebig kompliziert zusammengesetzte Datenstrukturen definiert und durch eigene Variablen bezeichnet werden. Zu den strukturierten Datentypen zählen: • • • • • • Mengen, Arrays, Listen und Matrizen, Tabellen und Relationen, Bäume und Graphen, Files, Programme und Objekte, Klassen und Methoden. 2.6.3.1 Mengen Prinzipiell ist eine Menge definiert als eine Zusammenfassung von wohl unterscheidbaren Objekten zu einem Ganzen (Bild 1.22). Die einzelnen Objekte bezeichnen wir als Elemente der Menge ( x ∈ M ). Um eine endliche Menge von Elementen eines Datentyps T zu definieren, kann der folgende Typ in vielen Programmiersprachen deklariert werden: set of T Bild 1.22 Eine Menge Eine ein-, zwei- oder mehrdimensionale Anordnung von Zahlen und Strings in geordneten oder ungeordneten Mengen ermöglicht hohe Flexibilität zur Manipulation von Daten. Ein „set“ ist eine Zusammenfassung von Elementen des gleichen Grundtyps – im Gegensatz zu Arrays aber ohne Rangordnung. Daher können einzelne Mengenelemente auch nicht über einen Index angesprochen werden. Die Reihenfolge der Elemente in der Menge ist nicht definiert. 2.6.3.2 Arrays Ein Array wird oft einfach als „Feld“ bezeichnet und ist eine geordnete Menge gleichartiger Datentypen (Bild 1.23), wobei auf die Elemente mit Hilfe eines Index I zugegriffen werden kann: type arraytyp = array [I] of grundtyp In manchen Programmiersprachen lautet das Schlüsselwort nicht Array, sondern dim (dimension). Bild 1.23 Ein Array 57 IK_1_Datenstrukturen.fm Seite 58 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.6.3.3 Listen Eine Liste ist eine verkettete Folge von elementaren oder strukturierten Datentypen. Eine Liste (list) ist ein vereinfachter Graph, denn jeder Knoten außer den beiden Endknoten ist mit genau zwei anderen Knoten über je eine Kante verbunden. Von den beiden Listenenden gehen jeweils nur eine Kante ab. Eine lineare Liste ist eine durch Zeiger verkettete Folge von Elementen gleichen Datentyps (üblicherweise Records). Jedes Element, bis auf das letzte, hat genau einen Nachfolger. Die lineare Liste ist die wichtigste dynamische Datenstruktur und wird mit Hilfe von Zeigern realisiert. Lineare Listen werden weiter unterteilt in einfach verketteten und doppelt verketteten Listen: Bild 1.24 Einfach und doppelt verkettete lineare Liste Listen haben folgende Eigenschaften: • • • • Ihre Größe kann zu- und abnehmen, beliebige Knotenzahl ist möglich, Elemente können in effizienter Weise umgeordnet werden, einziger Nachteil: Der Zugriff muss über den Listenkopf erfolgen. Die Darstellung einer Liste in Pascal könnte wie folgt aussehen: TYPE Liste = RECORD ende1, ende2 :^Listenknoten END; Listenknoten = RECORD nutzinformation : IrgendeinTyp; vorgänger :^Listenknoten; 58 IK_1_Datenstrukturen.fm Seite 59 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen nachfolger :^Listenknoten END; VAR liste: ^Liste; l,l1,l2: ^Listenknoten; Der Knoten, auf den ende1 zeigt, hat keinen Vorgänger, und der Knoten, auf den ende2 zeigt, hat keinen Nachfolger. In diesen Fällen besitzen die Komponenten-Vorgänger bzw. -Nachfolger den vordefinierten Wert NIL, der anzeigt, dass die Komponenten zur Zeit auf keinen Knoten verweisen. Gebräuchliche Operationen auf Listen sind • • • • • • das Erzeugen eines Listenknotens (neuerknoten(l1)), das Einfügen eines Knotens nach oder vor einem anderen Knoten (liste.einfügenach(l,l1), liste.einfügevor(l,l2)), das Entfernen eines Knotens (liste.enfernen(l)), das Verweisen auf den Vorgänger bzw. Nachfolger (liste.nächster(l),liste.voriger(l)), das Erfragen, ob die Liste leer ist (liste.leer), und das Feststellen der Anzahl der Listenknoten (liste.länge). 2.6.3.4 Matrizen Ein eindimensionales Array (Feld) entspricht einem Vektor, ein mehrdimensionales Array einer Matrix. Eine Matrix ist nichts anderes als eine mehrdimensional geordnete Menge von gleichartigen Datentypen. In der Mathematik werden Matrizen für die verschiedensten Zwecke eingesetzt. Ihre wesentlichen Merkmale sind: • • die lineare Anordnung ihrer Komponenten in mehreren Dimensionen und die Gleichartigkeit aller Komponenten. Matrixkomponenten werden durch einen Indexvektor identifiziert. In Anwendungen spielt die Art und Weise, wie Matrizen im Speicher abgelegt werden und wie der Zugriff auf ihre Komponenten erfolgt, eine wesentliche Rolle. Eine Matrix mit z.B. 1000 x 1000 Komponenten benötigt bei der Speicherung als zweidimensionaler Vektor eine Million Speicherzellen! Sind aber nur die Haupt- und Nebendiagonalen von Null verschieden, so reduziert sich der Platzbedarf auf rund 3000 Speicherzellen. 59 IK_1_Datenstrukturen.fm Seite 60 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.6.3.5 Tabellen und Relationen Beim Datentyp Tabelle werden Informationen unter einem bestimmten „Schlüssel“ gespeichert. Über diesen Schlüssel können die Informationen wieder abgerufen werden. Sowohl Schlüssel als auch Information können dabei einen beliebigen Datentyp haben. Relation = allg. jede Beziehung zwischen Datensätzen Im Bereich der Datenbanken (siehe Band 2, Modul 3) haben relationale Datenbanken eine lange Tradition. Daten werden in Tabellen gespeichert und können durch Relationen verknüpft werden. Die Relationen selbst werden in Form von Tabellen abgelegt. Eine Tabelle besteht dabei aus n Zeilen und m Spalten, ist also eine zweidimensionale geordnete Struktur. Oft enthält eine Spalte nur Elemente eines vorgegebenen Datentyps. Die Anzahl der Spalten wird als konstant betrachtet und ist in der Regel bei Anlegen der Tabelle festgelegt. Die einzelnen Datensätze werden in neue Zeilen eingefügt bzw. gelöscht. Die Zeilenzahl einer Tabelle ist damit flexibel. 2.6.3.6 Bäume und Graphen Achtung: Graph nicht mit Graf verwechseln! Bäume und Graphen sind Datenstrukturen, die aus Knoten und Kanten bestehen: Eine Kante verbindet stets zwei Knoten und kann somit als ein Paar von Knoten verstanden werden. Graphen Ein ungerichteter Graph G besteht aus zwei Mengen: einer Menge N von Knoten (nodes) und einer Menge V von Kanten (vertices), d.h. G = (N, V). Eine Kante a aus V verbindet stets zwei Knoten A und B aus N miteinander. Wir schreiben a = {A,B} = {B,A}. Die Anzahl der Kanten, die mit dem Knoten verbunden sind, wird der Grad eines Knotens genannt. Der ungerichtete Graph in Bild 1.25 (oben) hat die Knoten A, B und C und die Kanten a={A,B}={B,A}, b={A,C}={C,A} und c={B,C}={C,B}. Neben den ungerichteten Graphen existieren auch gerichtete Graphen, deren Kanten mit einer Vorzugsrichtung versehen sind. Bei ihnen sind die Kanten a={A,B} und a´={B,A} verschieden. Dies wird in der grafischen Darstellung durch einen Pfeil gekennzeichnet (Bild 1.25 unten). Die Anzahl der auf einen Knoten zeigenden Kanten wird Ingrad des Knotens, die Anzahl der aus dem Knoten herausgehenden Kanten wird Ausgrad genannt. Bild 1.25 Ungerichteter (oben) und gerichteter Graph (unten) 60 Die Kanten ungerichteter Graphen stellen nur die Beziehungen zwischen den Knoten dar, weisen jedoch keine Richtung aus. Sie können durch äquivalente gerichtete Graphen ausgedrückt werden, bei denen jeder Kante des IK_1_Datenstrukturen.fm Seite 61 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen ungerichteten Graphen zwei Kanten des gerichteten Graphen zugeordnet werden, die jedoch einander entgegengesetzt ausgerichtet sind. Ein Pfad zwischen zwei Knoten A und B existiert genau dann, wenn eine Folge aus Kanten und Knoten existiert, die von Knoten A ausgeht und zu Knoten B führt. Ein gerichteter oder ungerichteter Graph besitzt einen Zyklus, wenn von einem Knoten ein Pfad über mindestens einen weiteren Knoten wieder zu dem ersten Knoten zurück existiert. Ein Graph, der keine Zyklen besitzt, wird zyklenfrei genannt. Im Gegensatz zu ungerichteten Kanten können gerichtete Kanten direkt auf Variablen eines Datentyps abgebildet werden. Das ist etwas, das praktisch in allen modernen Programmiersprachen vorkommt: der Zeiger (pointer). Ein Knoten kann z.B. in folgender in Pascal formulierter Datenstruktur abgebildet werden: Pointer verweisen (zeigen) auf Daten TYPE Knoten = RECORD knoteninhalt : IrgendeinTyp; kanten : ^Kantenliste END; Kantenliste = RECORD kante : ^Knoten; nächsteKante : ^Kantenliste END; VAR graph, k, k1, k2 : ^Knoten Bäume Ein Baum (Bild 1.26) ist ein gerichteter Graph mit Knoten, auf die – bis auf eine Ausnahme – nur jeweils eine Kante zeigt. Die Ausnahme ist die Wurzel des Baumes. Sie besitzt keine eingehende Kante. Von den Knoten eines Baumes weisen ein oder auch mehrere Kanten zu weiteren Knoten, deren ausgehende Kanten wiederum auf Knoten verweisen können. Ein Knoten wird – zusammen mit allen über seine Kanten referenzierten Knoten, dessen Referenzen, usw. – Teilbaum genannt (Bild 1.26). 61 IK_1_Datenstrukturen.fm Seite 62 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Knoten, von denen keine Kanten ausgehen, werden Blätter genannt. Alle anderen Knoten heißen innere Knoten. Die Anzahl der Kanten von der Wurzel des Baumes zu einem Knoten heißt die Weglänge des Knotens. Die Wurzel hat also die Weglänge 0. Die größte Weglänge, über alle Knoten betrachtet, heißt Tiefe (bzw. Höhe) des Baumes. B-Bäume = balanced (ausgeglichen) Einem Baum, dessen Knoten nur jeweils eine ausgehende Kante besitzen, entspricht eine einfach verkettete Liste (Bild 1.24). Die häufigste Baumart ist der binäre Baum, dessen Knoten genau zwei ausgehende Kanten besitzen, die meist mit links und rechts bezeichnet werden. Besitzen Baumknoten mehr als zwei ausgehende Knoten, so werden die dazugehörenden Bäume B-Bäume oder auch Vielweg-Bäume genannt (siehe weiterführende Literatur z.B. OTTMANN & WIDMAYER (2002), SEDGEWICK (1997) oder GOODRICH & TAMASSIA (1998)). Bäume werden meistens dazu benutzt, um Daten im Arbeitsspeicher oder auf Massenspeichern geordnet abzulegen und schnell wiederzufinden. Aus diesem Grund besitzen die Knoten neben den Nutzinformationen und den Verweisen auf die nachfolgenden Knoten auch einen oder bei B-Bäumen mehrere Schlüssel, nach deren Werten der Knoten in den Baum eingefügt wird. Zudem existiert eine Ordnungsrelation „kleiner oder gleich“. Diese gibt Antwort darauf, ob der Schlüssel kleiner oder gleich einem anderen Schlüssel ist. Dies ist notwendig, da Schlüssel nicht nur Zahlen sondern auch beliebig komplexere Strukturen sein können, auf denen sich eine Ordnung definieren lässt. Beim binären Baum besitzt jeder Knoten höchstens zwei Nachfolger. Er lässt einfaches Suchen und Navigieren zu, z.B. mit Hilfe von Ja-Nein- bzw. Links-Rechts-Abfragen. Sind den Nachfolgern die Wahrheitswerte „Wahr“ oder „Falsch“ zugeordnet, wird von einem logischen Baum gesprochen. Verschiedene Suchalgorithmen auf Baumstrukturen basieren auf binären Bäumen. Sie werden deshalb auch Suchbäume genannt. Bild 1.26 Die Elemente und die Struktur eines Baumes mit der Höhe h = 3; die Anzahl der Kanten von der Wurzel bis zu einem Knoten heißt Weglänge; ein Knoten auf der Stufe i hat die Weglänge i 62 IK_1_Datenstrukturen.fm Seite 63 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Ein binärer Baum kann in der Sprache Pascal wie folgt dargestellt werden: VAR wurzel, k: ^Knoten; TYPE Knoten = RECORD schluessel: IrgendeinTyp; nutzinformation: IrgendeinWeitererTyp; links, rechts: ^Knoten END; Die Operationen auf einem binären Baum umfassen beispielsweise: • • • • • das Erzeugen eines Baumknotens (neuerknoten(k)), das Einfügen eines Knotens in einen Baum anhand des eingetragenen Schlüssels und der auf ihm definierten Ordnungsrelation (wurzel.einfuege(k,relation)), das Löschen eines Knotens aus dem Baum (wurzel.loesche(k)), das Suchen nach einem Knoten anhand eines Schlüssels (wurzel.suche(schluessel,relation)) (zurückgegeben wird ein Zeiger auf den gefundenen Knoten oder NIL, wenn kein passender Knoten gefunden wurde) und das Traversieren des Baumes, d.h. das Ausführen einer Operation auf jeden Baumknoten (wurzel.traversiere(operation)). Das Suchen in einem Baum ist sehr einfach, da ab der Wurzel für jeden besuchten Knoten nur die folgenden Fragen beantwortet werden müssen: • • • Stimmen der vorgegebene Schlüssel und der Knotenschlüssel überein, so ist der Knoten gefunden. Ist der vorgegebene Schlüssel von der Ordnungsrelation her kleiner als der Knotenschlüssel, so befindet sich der gesuchte Knoten (wenn überhaupt) in dem linken Teilbaum des aktuellen Knotens. Ist der vorgegebene Schlüssel größer als der Knotenschlüssel, so befindet sich der gesuchte Knoten (falls er existiert) im rechten Teilbaum des aktuellen Knotens. Bäume werden für Darstellung von Dateien und Datensätzen, beim strukturierten Programmieren, bei Suchalgorithmen und Entscheidungsverfahren verwendet. Der große Vorteil liegt in der Möglichkeit, Informationen so zu ordnen, dass schnell und systematisch auf sie zugegriffen werden kann. 63 IK_1_Datenstrukturen.fm Seite 64 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.6.3.7 Files Files sind ein Konzept, das in Zusammenhang mit Betriebssystemen (siehe Modul 2) entwickelt wurde: Ein File ist eine geordnete Menge von Bytes. Es kann selbst z.B. Zahlen, Zeichen usw. enthalten. Files sind lineare Folgen von Einzelelementen, die nicht in beliebiger Reihenfolge verarbeitet werden können. Files können nur sequentiell verarbeitet werden, d.h. elementweise von vorne nach hinten. Der Nachteil der eingeschränkten Verarbeitungsmöglichkeiten (nur sequentiell gegenüber beliebig) wird durch unbeschränkte Größe ausgeglichen: Files können (theoretisch) beliebig viele Elemente enthalten (einschließlich überhaupt keine). Aus technischer Sicht gibt es natürlich eine Grenze, weil die Speicherkapazität von Computer-Systemen endlich ist. Ein File ohne Inhalt (d.h. mit null Elementen) wird als leer bezeichnet. 2.6.3.8 Programme Ausführbare Programme sind spezielle geordnete Mengen von Daten (physikalisch von Bytes), die der Prozessor eines Computers ausführen kann. Es wird unterschieden zwischen Programmcode (auch „Quellcode“ genannt) und Maschinencode (auch „Bytecode“ genannt). Der Programmcode besteht aus Files und ist in einer künstlichen Sprache (Programmiersprache, Band 2, Modul 3) geschrieben. Der Maschinencode hingegen besteht auf der untersten Ebene nur aus Binärcode („0“ und „1“) und kann vom Prozessor (oder einer virtuellen Maschine) direkt ausgeführt werden. 2.6.3.9 Objekte, Klassen und Methoden Ab ca. 1990 wurden objektorientierte Datenstrukturen in viele Programmiersprachen eingeführt. Die Objekte sind dabei wieder verwendbare „Bausteine“. Die Klassen sind flexible „Ansammlungen“ verschiedenster elementarer und zusammengesetzter Datentypen. Klassen können weitere Klassen und Programme – die so genannten Methoden – enthalten. Prinzip der Objektorientierung ist es, Objekte nur von außen zu betrachten und ihren inneren Aufbau zu ignorieren – ihre Struktur wird durch Klassen festgelegt. Objekte, die nach der Struktur einer Klasse aufgebaut sind, sind Instanzen dieser Klasse. Objekte erledigen ihre Aktivitäten praktisch in „eigener Verantwortung“. Für die Softwareentwicklung (Modul 6) bedeutet das mehr Konfiguration, Ergänzung und Anpassung, statt einer kompletten Neuentwicklung. 64 IK_1_Datenstrukturen.fm Seite 65 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 2.7 Abstrakte Datentypen Die bis jetzt vorgestellten Datentypen sind in den meisten Programmiersprachen implementiert, daher sprachen wir auch von konkreten Datentypen. Die Einführung konkreter Datentypen war ein bedeutender Schritt in der Entwicklungsgeschichte der Programmiersprachen. Erst die Einführung von Abstraktionsmechanismen erlauben den Programmierern, Algorithmen aus ihrer Umwelt zu entwickeln – ohne die Details des Computersystems zu kennen. Komplexere Datenmodelle besitzen (manchmal) auch Strukturen, die über der Abstraktionsebene von strukturierten Datentypen liegen. Diese können in Klassen eingeteilt werden, zu denen ein generischer Datentyp definiert werden kann. Auf solche Datentypen können alle in einer Klasse vorkommenden Strukturen zurückgeführt werden. Solche generischen Datentypen können in sowohl in objektorientierten als auch in nichtobjektorientierten Sprachen realisiert werden und werden als abstrakte Datentypen (ADT) bezeichnet. Ein abstrakter Datentyp präsentiert sich einem Programmierer wie ein in der Programmiersprache schon verfügbarer Datentyp, auf den eine definierte Menge von Operationen anwendbar ist. Der abstrakte Datentyp muss jedoch in nicht-objektorientierten Programmiersprachen basierend auf schon vorhandenen Datentypen definiert worden sein, wobei Operationen in Ablaufkonstrukten der Programmiersprache ausformuliert sein müssen. Generisch aus lat. genus „Art, Gattung“ sind Funktionen oder Operatoren, die unabhängig vom verwendeten Datentyp immer dieselbe Aufgabe ausüben Beispiel Vektor Vn als abstrakter Datentyp: Ein Vektor Vn ist ein n-Tupel von: Vn = (v1, v2, ... vn). Um z.B. einen Punkt im dreidimensionalen Raum zu beschreiben, kann ein Tripel V3 = (x, y, z) verwendet werden bzw. V2 = (x, y) für einen Punkt in der Ebene. Dabei ist es für die Operationen unerheblich, ob die Komponenten des Vektors ganze oder reelle Zahlen sind. Mit Vektoren können neben den Grundrechenarten Addition, Subtraktion und komponentenweiser Multiplikation mit einem Faktor auch das Skalarprodukt und das Kreuzprodukt (für n=3) gebildet werden. Bei allen Operationen bis auf das Skalarprodukt ist das Ergebnis wieder ein Vektor, beim Skalarprodukt hat das Ergebnis den gleichen Typ wie die Komponenten. Beispiel: In der Programmiersprache Ada (Modul 2) kann ein objektorientierter Datentyp Vektor folgendermaßen beschrieben werden (Bild 1.27): Die Deklarationen im generic-Teil legen die grundlegenden Typen, Variablen und Operationen fest, die der Anwender des abstrakten Datentyps bei dessen Benutzung näher zu spezifizieren hat. In der package-Deklaration werden der Datentyp vektor und die auf ihn anwendbaren Operationen beschrieben. Diese beiden Teile sind dem Benutzer sichtbar. Der darauf fol- 65 IK_1_Datenstrukturen.fm Seite 66 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen gende Teil package body enthält die Implementation des abstrakten Datentyps. Er wird vor dem Benutzer versteckt gehalten. Bild 1.27 Ein Beispiel in der Sprache Ada In diesem Beispiel lassen sich generell zwei wichtige Eigenschaften von modernen Programmiersprachen erkennen: • • der Polymorphismus von Operationen und das Überladen von Operatoren. Polymorphismus drückt sich im Beispiel darin aus, dass zwei Operationen „*“ deklariert werden, die sich nur durch die Typen der Übergabe- und Rückgabeparameter unterscheiden. Dadurch können für vom Sinn her gleichartige Operationen auch die gleichen Namen benutzt werden. Das Überladen von Operatoren ist die Möglichkeit, Funktionsnamen nicht nur aus Buchstaben und Ziffern zu bilden, sondern auch Operationszeichen wie +, *, / zuzulassen, die normalerweise nur auf Werte von elementaren Datentypen anwendbar sind. Dadurch können Operationen mit abstrakten Datentypen so kurz wie mit elementaren ausgedrückt werden. Allerdings wird dadurch die Analyse von Programmen bei Fehlern erschwert, da neben den Operatoren auch die Operandentypen für eine eindeutige Kennzeichnung der aufgerufenen Operationen notwendig sind. 66 IK_1_Datenstrukturen.fm Seite 67 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 3 Beispielalgorithmen Die Definition „Algorithmus“ – als allgemeines Lösungsverfahren für ein Problem – impliziert, dass zu jedem lösbaren Problem auch mindestens ein Lösungsverfahren existiert. Es kann sogar bewiesen werden, dass zu jedem Algorithmus unendlich viele verschiedene Algorithmen existieren, die das gleiche Problem lösen. Um nun diese riesige Menge von Algorithmen besser handhaben zu können, ist es sinnvoll, eine Einteilung nach Kriterien vorzunehmen. So können z.B. Algorithmen, die ein bestimmtes Problem lösen, zu einer eigenen Klasse zusammengefasst werden. Da auch Probleme zu Klassen zusammengefasst werden können, ist es sinnvoll, auch auf diese Weise eine entsprechende Einteilung von Algorithmen vorzunehmen, z.B.: • • • Sortieralgorithmen, Suchalgorithmen, Codierungsalgorithmen usw. Diese Beispiele sollen nur einen groben Eindruck von der Fülle an existierenden Algorithmen, Algorithmenklassen und -klassifikationen geben. Sie erheben keinen Anspruch auf Vollständigkeit, stellen jedoch wichtige Vertreter aus der Menge der Algorithmen dar. 3.1 Sortieralgorithmen Das Sortieren von Objekten nach bestimmten Kriterien ist eine der häufigsten Aufgaben, die mit Computersystemen gelöst werden. Die Sortierverfahren können beliebige Objekte (nicht nur Zahlen) sortieren – vorausgesetzt, es kann auf diesen eine Ordnungsrelation definiert werden. Grundlegende Sortieralgorithmen umfassen folgende Strategien: • • • • Sortieren durch Austauschen (z.B. Bubblesort, Quick Sort), Sortieren durch Auswählen (z.B. Heapsort), Sortieren durch Einfügen (z.B. lineare Listen und Bäume) und Sortieren durch Verschmelzen (Sortieren durch Mischen). 3.1.1 Bubblesort Bubblesort ist ein einfaches Verfahren zum Sortieren eines linearen Arrays (Feldes). Bubblesort verfährt nach folgender Methode: Es wird die Liste a[1] ... a[N] der Datensätze durchlaufen und dabei werden je zwei benachbarte Elemente betrachtet: [i] und a[i+1]. Ist a[i].key > a[i+1].key, so wird a[i] und a[i+1] vertauscht. Das Durchlaufen des Arrays wird so lange wiederholt, bis keine Elemente mehr vertauscht wurden: Das 67 IK_1_Datenstrukturen.fm Seite 68 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Array ist sortiert. Das Verfahren hat seinen Namen, da bei jedem Schleifendurchlauf benachbarte Elemente miteinander verglichen werden und das jeweils größere Element nach oben „steigt“. Sie steigen wie Luftblasen nach oben bzw. rechts auf. Beispiel: Feld B = 15,2,43,17,4,8,47 Nach 1. Durchlauf: 2,15,17,4,8,43,47 Nach 2. Durchlauf: 2,15,4,8,17,43,47 Nach 3. Durchlauf: 2,4,8,15,17,43,47 Keine Vertauschungen mehr bei 4. Durchlauf, d.h. das Feld ist sortiert. 3.1.2 Selection Sort Algorithmus: • • • 1. Finde das kleinste Element im Feld und tausche es mit dem ersten Element. 2. Finde das zweitkleinste Element und tausche es mit dem zweiten Element. 3. Wenn das größte Element am letzten Platz steht, ist die Datei sortiert. Da jedes Element im Schnitt einmal bewegt wird, ist dieses Verfahren dazu geeignet, Dateien mit sehr großen Datensätzen und kleinen Schlüsseln zu sortieren. Beispiel mit Zahlen: 2 8 5 7 1 (das kleinste Element wird gesucht und mit dem auf Platz 1 vertauscht) 1 8 5 7 2 (das zweitkleinste Element wird gesucht und mit dem auf Platz 2 vertauscht) 1 2 5 7 8 (das 3. Element wird gesucht, es ist auf der richtigen Position) 1 2 5 7 8 (das 4. Element wird gesucht, es ist auf der richtigen Position) 1 2 5 7 8 (das 5. Element wird gesucht, es ist auf der richtigen Position) 68 IK_1_Datenstrukturen.fm Seite 69 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 3.1.3 Quicksort Quicksort wurde von HOARE (1960) entwickelt und ist ein Mehrzwecksortierverfahren, das in vielen Situationen weniger Ressourcen erfordert als andere Algorithmen. • • Vorteile: Quicksort läuft „in Place“ (am Ort) ab und es ist gut erforscht. Nachteile: rekursiv, wenige Operationen, störanfällig, innere kurze Schleife. Algorithmus: Quicksort besteht im Wesentlichen aus dem Zerlegen der Datei in zwei Teilen und dem anschließenden Sortieren der Teile unabhängig voneinander. • • • • • • 1. Zuerst wird ein beliebiges Element gewählt, das in die richtige Position gebracht werden soll. 2. Dann wird das Feld von links untersucht, bis ein größeres Element gefunden wird. 3. Danach wird das Feld von rechts untersucht, bis ein kleineres oder gleiches Element gefunden wird. 4. Jetzt werden die beiden Elemente vertauscht. 5. Wenn sich die beiden Zeiger treffen, wird das Element, dass auf die richtige Position gebracht werden soll, mit dem Element vertauscht, das sich am weitesten links von der rechten Seite befindet. 6. Danach wird dieser Vorgang jeweils für die daraus entstehenden Teildateien rekursiv angewendet, bis sie vollständig sortiert sind. 3.1.4 Insertion Sort Der Insertion Sort arbeitet schneller (N²/4 Vergleiche und N²/8 Austauschoperationen) als der Bubblesort Algorithmus (N²/2 Vergleiche und N²/2 Austauschoperationen). Der Selection Sort benötigt N²/2 Vergleiche und N Austauschoperationen. Allerdings sind alle diese Sortierverfahren nicht für größere Datenmengen geeignet. Algorithmus: • • • 1. Betrachte ein Element. 2. Füge dieses Element an seinen jeweils richtigen Platz zwischen den bereits betrachteten Elementen ein, indem das größere um eine Position nach rechts bewegt und das Element dann auf dem freigewordenen Platz eingefügt wird (Bild 1.22) . 3. Das Ende ist dann erreicht, wenn man das letzte Feld betrachtet hat. Bild 1.28 Beispiel für die Wirkungsweise von Insertion Sort 69 IK_1_Datenstrukturen.fm Seite 70 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 3.1.5 Shell Sort Shell Sort ist eine Erweiterung des Insertion Sort, wobei aber eine Erhöhung der Geschwindigkeit dadurch erzielt wird, dass weit entfernte Elemente ausgetauscht werden können. Algorithmus: • • • • • 1. Zuerst wird ein bestimmter Abstand zwischen den jeweiligen Elementen gesucht, z.B. 4 Elemente Unterschied. 2. Es werden das 1. und das 5. Element verglichen, das 2. und das 6. Element verglichen usw. (eine solche Datei wird „4-sortiert“ genannt). 3. Die Elemente werden – wenn es notwendig ist – vertauscht. 4. Wenn man am Ende der Datei ist, so wird ein neuer, kleinerer Abstand zwischen den Elementen gewählt. 5. Wenn der Abstand nur mehr aus 1 Element Unterschied besteht, wird die gesamte Datei mit dem Bubblesort sortiert. Bei Dateien mit vielen Elementen wird der Abstand entsprechend größer gewählt. Die besten Abstände (also der Abstand bei dem das Sortieren am effizientesten ist) zwischen den einzelnen Elementen Abstand * 3 +1. Die Beschreibung der Effizienz von Shell Sort ist sehr ungenau, da bis jetzt noch niemand den Algorithmus genau analysieren konnte. Bis zu etwa 5000 Elementen ist der Shell Sort von allen bisherigen Sortierverfahren das beste und wird auch bei vielen Anwendungen benutzt. 3.1.6 Heapsort Oft müssen andere Operationen, wie das Einfügen, Löschen des größten Elements, Ersetzen, Verändern, Löschen eines beliebigen Elements und das Zusammensetzen mehrerer Daten, möglich sein. Dafür eignet sich der Heapsort („Sortierung von Haufen“) sehr gut. Der Algorithmus wurde von WILLIAMS (1964) entwickelt und basiert auf dem Treesort-Verfahren von FLOYD (1962). Die Datenstruktur des Heaps ist ein vollständiger, nicht sortierter, binärer Baum. Dieser Baum muss zwei Bedingungen erfüllen: • • 70 1. Jeder Knoten muss größer als sein Nachfolger sein, das heißt, der größte Schlüssel ist die Wurzel. 2. Wenn ein Knoten die Position j hat, muss sein Nachfolger die Position j*2 oder j*2+1 haben. IK_1_Datenstrukturen.fm Seite 71 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Algorithmus: Zunächst wird ein Heap aufgebaut, der die zu sortierenden Elemente enthält: • • • • • • 1. An der (abrunden(letzten Position/2)) suchen (z.B. 9/2=4.5 -> 4). 2. Heapbedingung überprüfen (Element an Position j muss größer sein als Element an der Position j*2 und j*2+1). 3. Wenn es notwendig ist, Elemente tauschen. 4. Punkt 2 und 3 wiederholen, bis man die verglichenen Elemente nicht mehr tauschen muss. 5. Position um 1 vermindern. 6. Punkt 1 bis 5 wiederholen, bis man die erste Position erreicht. Danach werden sie in der richtigen Reihenfolge entfernt, und das jeweilige entfernte Element wird gespeichert („Top-down-Heap“): • • 1. Erstes Element mit letztem Element tauschen. 2. Neuen Heap aufbauen, ohne das letzte Element zu berücksichtigen. Der Heapsort ist eine effiziente Sortiermethode (es gibt keine ungünstigen Fälle, es ist kein zusätzlicher Speicherplatz notwendig), allerdings ist er nur halb so schnell wie der Quicksort. Die für eine Sortierung benötigte Zeit t = n × log (n), hängt also von der Anzahl n der zu sortierenden Elemente ab. Damit gehört Heapsort zu den schnellsten Sortieralgorithmen. Nur Quicksort ist noch schneller. 3.2 Suchalgorithmen Suchen wird in der Informatik als Auffinden einer bestimmten Information definiert. Dieser Begriff ist abzugrenzen von Durchsuchen (z.B. einer Datei oder eines Datenträgers), bei dem jedes Element genau einmal bearbeitet wird. Suchalgorithmen sind Verfahren um in einem Datenbestand Objekte zu finden, die eine bestimmte Bedingung – das Suchkriterium – erfüllen. Die folgenden Suchalgorithmen sind verbreitet: • • • lineare (sequentielle) Suche, binäre Suche und die Suche auf einem (binären) Baum. Oft wird in diesem Zusammenhang von einem „Schlüssel“ gesprochen, der die Datensätze kurz und eindeutig kennzeichnen soll. 71 IK_1_Datenstrukturen.fm Seite 72 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 3.2.1 Lineare Suche Bei einer linearen Suche werden sequentiell (nacheinander) die Objekte eines „Behälters“ durchgesehen – bis ein Objekt gefunden wird, das das Suchkriterium erfüllt. Anschließend wird in gleicher Weise fortgesetzt, um weitere Objekte zu finden. Dieses Verfahren ist einfach, aber zeitaufwendig. Allgemein lässt sich dieses Suchproblem so definieren: • • In einem Behälter B befindet sich eine Anzahl von Elementen, Prüfe, ob ein Element e ∈ Β existiert, das die Eigenschaft E(e) erfüllt „Behälter“ kann dabei eine beliebige Datenstruktur sein, wie z.B. Listen, Arrays, Mengen, Bäume, Graphen usw., der Anfangszustand des Behälters kann sowohl sortiert als auch unsortiert sein. Jedes Element wird einmal „angefasst“ und überprüft. Der ungünstigste Fall (worst case) kann dann sein, das alle Elemente einmal angefasst werden müssen. Vorteile: • • einfach zu programmieren; ist bei einfachen und kurzen Listen schneller als die binäre Suche. Nachteile: • • ist nicht geeignet für das Suchen in verketteten Listen und Bäumen; Zeitaufwand ist linear ansteigend, das Verfahren wird daher langsam. 3.2.2 Binäre Suche In einer auf- oder absteigend sortierten Liste wird fortgesetzt der Bereich halbiert, in dem sich ein gesuchtes Objekt noch befinden kann. Ein solcher Algorithmus arbeitet schnell, da er bereits mit wenigen Schritten zum Ziel kommt: Eine Verdoppelung der Objektzahl erfordert im Mittel lediglich eine zusätzliche Bereichshalbierung. Beispiel: Suchen einer Telefonnummer in einem Telefonbuch: • • • • 72 Aufschlagen des Telefonbuches in der Mitte, nachschauen, ob der gesuchte Name in der linken oder in der rechten Hälfte vorkommt, dann wiederholen des Vorganges mit der entsprechenden Hälfte, bis der Name gefunden wird. Meistens (spätestens) nach dem 10. Vergleich fündig. IK_1_Datenstrukturen.fm Seite 73 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 3.2.3 Suche auf einem binären Baum Alle Objekte werden aus einer nach dem Suchkriterium vorsortierten und aufsteigend nummerierten Liste in einen binären Baum (Kapitel 2.6.3.6) so einsortiert, dass die Einträge des linken Teilbaums kleinere Listennummern als der übergeordnete Knoteneintrag aufweisen. Entsprechend weisen die Einträge des rechten Teilbaums nach dem Knoteneintrag größere Einträge auf und das für alle Knoten. Die Suche beginnt oben an der Baumwurzel: Erfüllt der Wurzeleintrag das Suchkriterium, ist die Suche sofort erfolgreich. Wird nach einer kleineren Nummer als der des Wurzeleintrags gesucht, dann verzweigt man im Baum nach links in die nächste Knotenebene, sonst nach rechts. Anschließend setzt man an dem erreichten Knoten in gleicher Weise fort. Diese Suche endet nach (spätestens) so vielen Abfragen, wie Verzweigungen möglich sind. Damit ist die Suche auf einem binären Baum ein sehr effizienter Suchalgorithmus. Bei der Suche auf nicht binären, aber geordneten Baumstrukturen wie z.B. dem B-Baum können ähnliche Suchalgorithmen verwendet werden. Aber zusätzlich werden alle Nachfolger eines Knotens wie bei einer geordneten Liste durchsucht. Ein Baum, der speziell für effizientes Suchen eingerichtet ist, wird als Suchbaum bezeichnet. Von Bedeutung ist auch das Hash-Verfahren: Dabei handelt es sich um ein kombiniertes Speicherungs- und Suchverfahren, bei dem Datensätze gestreut gespeichert und die Adressen von Datensätzen aus den zugehörigen Schlüsseln errechnet werden. Gestreute Speicherung von Datensätzen bedeutet, dass bezüglich einer Nummerierung der gespeicherten Datensätze nach den Schlüsseln Lücken auftreten. Solche sind praktisch nur mit großem Aufwand zu vermeiden, wenn die Menge aller möglichen Schlüssel wesentlich größer als die Zahl der Datensätze ist. Eine direkte Adressierung der Datensätze nach den Schlüsseln hätte aber den Nachteil, dass unnötig viele Speicheradressen zur Verfügung gestellt werden müssen. Daher werden beim Hash-Verfahren die Datensätze einem Speicherbereich von passender Größe zugeteilt. Die Adressierung erfolgt indirekt, d.h. über eine Vorschrift, wie sich die Adresse aus den Schlüsseln berechnet. Diese Vorschrift wird Hash-Funktion genannt und wird so entworfen, dass die Adressen schnell zu berechnen sind und sich die Adressen gleichmäßig auf den Speicherbereich verteilen. Die Auflistung aller Funktionswerte einer Hash-Funktion wird Hash-Tabelle genannt. Hash-Verfahren werden auch bei Schachprogrammen verwendet, um identische Stellungen zu finden, die durch verschiedene Zugfolgen (die die Schlüssel bilden) erreicht werden. 73 IK_1_Datenstrukturen.fm Seite 74 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 4 Modulkurzzusammenfassung Algorithmen und Datenstrukturen sind zentral für die ganze Informatik. Ein Algorithmus dient zur Lösung allgemeiner Probleme und muss diskret, determiniert, eindeutig und endlich sein. Darstellungsmöglichkeiten von Algorithmen umfassen die Pseudo-Code Notation, Programmablaufplan (PAP) und Struktogramm. Im SoftwareEngineering (Modul 6) wird hauptsächlich mit so genannten Daten- und Funktionsmodellierungsmodellen gearbeitet (ERM, SADT, UML). Algorithmen werden entwickelt, indem Kontrollelemente zu komplexeren Abläufen zusammengesetzt werden: Elementare Operation (Verarbeitung), Sequenz (Abfolge) und Wiederholung (Schleife) reichen, um alles programmieren zu können, was überhaupt programmierbar ist. Komfortabel sind zusätzlich die parallele Ausführung, bedingte Ausführung, Unterprogramm und Rekursion. Eine Konstante ist ein Datenelement, dessen Wert sich bei der Ausführung eines Programms nicht ändert. Eine Variable hingegen ist ein Datenelement, dessen Wert sich während der Ausführung eines Programms ändern kann. Der Datentyp legt die Art der gespeicherten Information und deren Auswertemöglichkeit fest. Idealisierte Datentypen sind durch den beschränkten Speicherplatz in Computern nicht darstellbar, können jedoch für den theoretischen Entwurf von Algorithmen hilfreich sein. Die konkreten Datentypen werden oft als „die“ Datentypen bezeichnet und unterteilen sich in einfache Datentypen, strukturierte Datentypen und Zeigerdatentypen. Einfache Datentypen sind die elementaren Grundbausteine aller weiteren Daten. Sie sind nur als Ganzes manipulierbar und nicht weiter zerlegbar. Sie unterteilen sich in zwei Unterarten: ordinale Datentypen und Real-Datentypen. Zu den ordinalen Datentypen zählen: BOOLEAN, INTEGER und CHAR sowie die durch Einschränkung abgeleiteten Aufzählungsdatentypen und Teilbereichsdatentypen. In vielen Programmiersprachen können beliebig zusammengesetzte Datenstrukturen definiert und durch eigene Variable bezeichnet werden. Zu den strukturierten Datentypen zählen: Mengen, Arrays, Listen und Matrizen; Tabellen und Relationen; Bäume und Graphen; Files; Programme und Objekte, Klassen und Methoden. 74 IK_1_Datenstrukturen.fm Seite 75 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 5 Modulanhang 5.1 Literatur 5.1.1 Bücher AHO, ALFRED V.; ULLMAN, JEFFREY D. (1997): Informatik. Datenstrukturen und Konzepte der Abstraktion. Bonn: MITP-Verlag. BALZERT, HELMUT (1999): Lehrbuch Grundlagen der Informatik: Konzepte und Notationen in UML, Java und C++, Algorithmik und Softwaretechnik und Anwendungen. Berlin u.a.: Spektrum Akademischer Verlag. 467–652. BREUER, HANS (1995): dtv-Atlas zur Informatik: Tafeln und Texte. München: Deutscher Taschenbuch Verlag. 53–55. ERNST, HARTMUT (2000): Grundlagen und Konzepte der Informatik. Braunschweig: Vieweg. 410–661. FUTSCHEK, GERALD (1989): Programmentwicklung und Verifikation. Berlin, Heidelberg, New York: Springer. GOLDSCHLAGER, LES; LISTER, ANDREW (1990): Informatik – Eine moderne Einführung. 3. Auflage. München, Wien u.a.: Hanser Prentice Hall International. GOOS, GERHARD (2001): Vorlesungen über Informatik Band 2: Objektorientiertes Programmieren und Algorithmen. 3. Auflage. Berlin: Springer. GUMM, HEINZ-PETER; SOMMER, MANFRED (2000): Einführung in die Informatik. 4. Auflage. München, Wien: Oldenbourg. 271–356. HEUN, VOLKER (2000): Grundlegende Algorithmen: Einführung in den Entwurf und die Analyse effizienter Algorithmen. Braunschweig: Vieweg. JUNGNICKEL, D. (1990): Graphen, Netzwerke und Algorithmen. Mannheim, Wien, Zürich: BI-Wissenschaftsverlag. MEHLHORN, K. (1988): Datenstrukturen und effiziente Algorithmen. Band 1: Sortieren und Suchen. Stuttgart: Teubner. OTTMANN, THOMAS; WIDMAYER, P. (2002): Algorithmen und Datenstrukturen. Heidelberg u.a.: Spektrum. OTTMANN, THOMAS, Hrsg. (1998): Prinzipien des Algorithmenentwurfs. Heidelberg: Spektrum. SAAKE, GUNTER; SATTLER, KAI-UWE (2001): Algorithmen & Datenstrukturen: Eine Einführung mit Java. Hannover: Heise. 75 IK_1_Datenstrukturen.fm Seite 76 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen SEDGEWICK, ROBERT (1992): Algorithmen in C++. Bonn: Addison Wesley. SOLYMOSI, ANDREAS; GRUDE, ULRICH (2000): Grundkurs Algorithmen und Datenstrukturen: Eine Einführung in die praktische Informatik mit Java. Stuttgart: Vieweg. WIRTH, NIKOLAUS (1983): Algorithmen und Datenstrukturen. Stuttgart: Teubner. 5.1.2 Artikel BRANDENBURG, FRANZ J.; JÜNGER, MICHAEL; MUTZEL, PETRA (1997): Algorithmen zum automatischen Zeichnen von Graphen. Informatik-Spektrum, Vol. 20, Iss. 4, 199–207. RAUH, OTTO (1995): ERMded – eine Erweiterung des Entity-Relationship-Modells zur Modellierung deduktiver Informationssysteme. Informatik Forschung und Entwicklung, Vol. 10, Iss. 3, 128–138. ZIEGLER, BERNHARD (1996): ESS – Ein schneller Algorithmus zur Mustersuche in Zeichenfolgen. Informatik Forschung und Entwicklung, Vol. 11, Iss. 2, 69–83. ZELLER, ANDREAS (2001): Datenstrukturen visualisieren und animieren mit DDD. Informatik Forschung und Entwicklung, Vol. 16, Iss. 2, 65–75. 5.1.3 Books in English AHO, A. V. ; HOPCROFT, J. E.; ULLMAN, J. D. (1974): The Design and Analysis of Computer Algorithms. Reading (MA): Addison-Wesley. AHUJA, RAVINDRA K.; MAGNANTI, THOMAS L.; ORLIN, JAMES B. (1993): Network Flows: Theory, Algorithms, and Applications. Englewood Cliffs (NJ): Prentice Hall. CORMEN, THOMAS H.; LEISERSON, CHARLES E.; RIVEST, RONALD L. (1990): Introduction to Algorithms. Boston (MA): MIT Press. DAHL, O.-J.; DIJKSTRA, E. W.; HOARE, C. A. R. (1972): Structured Programming. London, New York: Academic Press. GOODRICH, M. T.; TAMASSIA, R. (1998): Data Structures and Algorithms in Java. New York: Wiley. HOROWITZ, ELLIS; SAHNI, SARTAJ (1983): Fundamentals of Data Structures. New York: Computer Science Press. KNUTH, D. E. (1973): The Art of Computer Programming: Volume 1: Fundamental Algorithms. Reading (MA): Addison Wesley. KNUTH, D. E. (1981): The Art of Computer Programming: Volume 2: Seminumerical algorithms. Reading (MA): Addison Wesley. 76 IK_1_Datenstrukturen.fm Seite 77 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen KOZEN, DEXTER C. (1991): The design and analysis of algorithms (Texts and Monographs in Computer Science). Berlin et al.: Springer. MEHLHORN, KURT (1984): Data structures and algorithms 1: Sorting and searching (EATCS Monographs on Theoretical Computer Science). Berlin et al.: Springer. MEHLHORN, KURT (1984): Data structures and algorithms 2: Graph algorithms and NPCompleteness (EATCS Monographs on Theoretical Computer Science). Berlin et al.: Springer. PAPADIMITRIOU, CHRISTOS H.; STEIGLITZ, KENNETH (1982): Combinatorial optimization: Algorithms and complexity. Englewood Cliffs (NJ): Prentice-Hall. SEDGEWICK, ROBERT (1997): Algorithms in C. Reading (MA): Addison-Wesley. SHAFFER, CLIFFORD A. (1997): A Practical Introduction to Data Structures and Algorithm Analysis: C++ Version. London: Prentice Hall. SHAFFER, CLIFFORD A. (1998): A Practical Introduction to Data Structures and Algorithm Analysis: Java Edition. London: Prentice Hall. STANDISH, THOMAS (1998): Data Structures in Java. Addison-Wesley. 5.1.4 Articles in English AGARWAL, PANKAJ K.; SHARIR, MICHA (1998): Efficient Algorithms for Geometric Optimization. ACM Computing Surveys, 30 (4), 412–458. BOYER, R. S.; MOORE, J. S. (1977): A fast string searching algorithm. Communcations of the ACM, 20 (10). GAEDE, VOLKER; GÜNTHER, OLIVER (1998): Multidimensional Access Methods. ACM Computing Surveys, 30 (2), 170–231. GUPTA, P.; CHAKRABARTI, P. P.; GHOSE, S. (1992): The Towers of Hanoi: Generalizations, Specializations, Algorithms. Int. Journal of Computer Mathematics, 46, 149–161. HOARE, C. A. R. (1961): Algorithm 64: Quicksort. Communications of the ACM, Vol. 4, Iss. 7, 321. HOARE, C. A. R. (1971): Proof of a program: FIND. Communications of the ACM, Vol. 14, Iss. 1, 39–45. SCANLAN, D. A. (1989): Structured flowcharts outperform pseudocode: An experimental comparison. IEEE Software, 6, 28-36. WIERINGA, ROEL (1998): A Survey of Structured and Object-Oriented Software Specification Methods and Techniques. ACM Computing Surveys, 30 (4), 459–527. 77 IK_1_Datenstrukturen.fm Seite 78 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 5.1.5 Journals Algorithmica (ISSN: 0178-4617 printed version; ISSN: 1432-0541 electronic version) | Springer Theory of Computing Systems, vorher: Mathematical Systems Theory (ISSN 14324350) | Springer Acta Informatica (ISSN: 0001-5903 printed version; ISSN: 1432-0525 electronic version) | Springer Discrete Applied Mathematics (ISSN: 0166-218X) | Elsevier Information Processing Letters (ISSN: 0020-0190) | Elsevier Informatik Forschung und Entwicklung (ISSN 0178-3564) Springer 5.2 Internet-Links Aktualisierte Internet-Links zu diesem Modul sind auf der Buchhomepage www.basiswissen-it.at unter IK – Modul 1: Algorithmen & Datenstrukturen verfügbar! 5.3 Prüfungsfragen Fragen-Typ 1: Dichotome Ja/Nein-Entscheidungen: 01 02 03 04 05 06 07 08 09 10 78 Determiniertheit heißt, dass bei gleichen Anfangs- und Randbedingungen stets dasselbe Endergebnis erhalten wird. Ein Datentyp beschreibt eine Verzweigung aufgrund einer eindeutigen Bedingung (Grundtyp). Struktogramme beschreiben den formalen Aufbau einer Datenstruktur und den formalen Aufbau einer Programmiersprache. Konstante repräsentieren einen Wert, der vor Programmausführung festgelegt wird und sich zur Ausführungszeit des Algorithmus ändert. Der Datentyp BOOLEAN umfasst nur die Werte TRUE (wahr) und FALSE (falsch). Der Datentyp INTEGER ist ein vordefinierter Datentyp und dient zur Darstellung von reellen Zahlen. Ein eindimensionales Array wird auch Feld genannt und entspricht einem Vektor, ein mehrdimensionales Array entspricht einer Matrix. Bubblesort ist eine Erweiterung des Insertion Sort und ist ein vollständiger binärer Baum. Ein Baum ist ein gerichteter Graph mit Knoten, auf die, bis auf eine Ausnahme, nur jeweils eine Kante zeigt. Quicksort besteht aus dem Zerlegen einer Datei in zwei Teile und dem anschließenden Sortieren der Teile unabhängig voneinander. Ja Nein Ja Nein Ja Nein Ja Nein Ja Nein Ja Nein Ja Nein Ja Nein Ja Nein Ja Nein IK_1_Datenstrukturen.fm Seite 79 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Fragen-Typ 2: Mehrfachauswahlantworten (Multiple Choice): 01 02 03 04 05 06 07 08 Beispiele für Algorithmen sind ... a) ... das Sortieren von Briefen. b) ... die Anleitung zur Behebung von Startproblemen bei Autos. c) ... die Regeln der Differentialrechnung. d) ... die Berechnung der Oberfläche einer Dose. Zu den elementaren Datentypen zählen ... a) ... Graphen. b) ... Byte. c) ... Zeichen. d) ... Mengen. Es kann alles programmiert werden mit den Elementen ... a) ... Rekursion + Verarbeitung + Sequenz. b) ... Verarbeitung + Wiederholung + Sequenz. c) ... Verarbeitung + Auswahl + Sequenz. d) ... Sequenz + Wiederholung + bedingter Ausführung. Struktogramme ... a) ... sind auch bei komplexen Problemstellungen sehr übersichtlich. b) ... sind gut zur Darstellung parallel ablaufender Prozesse geeignet. c) ... sind zur Darstellung von Entwicklungsprozessen gut geeignet. d) ... dienen zur Veranschaulichung von Programmabläufen. Zu den strukturierten Datentypen zählen ... a) ... Mengen. b) ... Graphen. c) ... Real-Datentyp. d) ... Files. Ordinale Datentypen umfassen ... a) ... Aufzählungsdatentypen. b) ... Zeigerdatentypen. c) ... Objekte, Klassen und Methoden. d) ... Tabellen und Relationen. Ausführbare Programme sind ... a) ... spezielle geordnete Mengen von Daten. b) ... spezielle geordnete Mengen von (physikalischen) Bytes. c) ... Ansammlungen elementarer Datentypen. d) ... lineare Folgen von Einzelelementen. Gebräuchliche Operationen auf Listen sind ... a) ... das Erzeugen eines Listenknotens. b) ... das Erzeugen eines Baumknotens. c) ... das Traversieren des Baumes. d) ... das Verweisen auf den Vorgänger bzw. Nachfolger. 5.4 Lösungen Lösungen zu Fragen-Typ 1: 01 Ja; 02 Nein; 03 Nein; 04 Nein; 05 Ja; 06 Nein; 07 Ja; 08 Nein; 09 Ja; 10 Nein Lösungen zu Fragen-Typ 2: Richtig sind: 01 b) c); 02 b) c); 03 b); 04 d); 05 a) b) d) 06 a); 07 a) b); 08 a) d 79 IK_1_Datenstrukturen.fm Seite 80 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 5.5 Übungen • • • Entwickeln Sie einen Algorithmus, der zwei Namenslisten vergleicht und die doppelt vorhandenen Namen in eine dritte Liste schreibt. Bei mehrfachem Aufscheinen gleicher Namen soll dieser nur einmal aufscheinen. Entwickeln Sie für eine (beliebige) Aufgabenstellung einen Programmablaufplan und ein Struktogramm. Vergleichen Sie nun die beiden Darstellungen und überlegen Sie deren Vorteile und Nachteile! Vergleichen Sie verschiedene Sortieralgorithmen. Stellen Sie in einer Tabelle deren Vorteile und Nachteile gegenüber und messen Sie deren Laufzeit. Was fällt Ihnen auf? 5.6 Diskussionsfragen • • • Informieren Sie sich zuerst über Algorithmen zur Lösung von linearen Gleichungssystemen und diskutieren Sie dann in der Gruppe darüber! Welche Ansätze sind vorteilhafter? Was gilt es zu beachten? Bilden Sie zwei Gruppen. Diskutieren Sie die Bedeutung des Gebietes „Algorithmen und Datenstrukturen“ für die Informatik. Eine Gruppe „verteidigt“ die Position – die andere „attackiert“. Jeder von Ihnen „übernimmt“ einen Datentyp und präsentiert diesen der Gruppe. Jeder soll versuchen, „seinen“ Datentyp möglichst positiv darzustellen. Jemand versucht nun, die Datentypen schlecht zu machen. 5.7 Timeline: Algorithmen und Datenstrukturen 1700 v. Chr. Papyrus Rhind: älteste schriftliche Rechenaufgabe (Ägypten). 300 v. Chr. EUKLID (365–300 v.Chr.) beschreibt einen Algorithmus zur Bestimmung des größten gemeinsamen Teilers (ggT) in seinem 7. Buch der Elemente. 230 v. Chr. ERATHOSTENES (276–197 v.Chr.) entwickelt einen Algorithmus zur Berechnung von Primzahlen (Sieb des Erathostenes). 800 MOHAMMED IBN MUSA ABU DJAFAR AL CHORESMI (780–850) beschreibt Vorgehensweisen für Testamentsvollstreckungen. Bildung des Begriffs Algorithmus aus seinem Namen und dem griechischen „arithmo“ für Zahl. 1574 Sammlung von Algorithmen im Rechenbuch von ADAM RIES (1492–1559). 1614 Nach 30 Jahren Arbeit wird die erste Logarithmentafel erstellt. 1703 Binäres Zahlensystem von LEIBNIZ. 1931 Unvollständigkeitssatz von GÖDEL. 1936 Church'sche These. 1960 HOARE stellt den Bubblesort-Algorithmus vor. 1972 Entwicklung der NP-Vollständigkeit zur Beschreibung algorithmischer Computer-Probleme. 80 IK_1_Datenstrukturen.fm Seite 81 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen 5.8 Glossar Algorithmus Beschreibung eines Informationsverarbeitungsmodells oder Prozessablaufs in einer Form, die von einer Maschine ausgeführt werden kann. Array (Feldtyp) ist die endliche Aneinanderreihung von Datenelementen gleicher Art in einem zusammenhängenden Speicherbereich. Zugriff mit Hilfe eines Index. Anweisung (statement) Bestandteile eines Blocks: Kontrollstruktur, Definition oder Ausdruck. Ausdruck (expression) Vorschrift zur Berechnung eines Wertes durch Kombination von Unterausdrücken mit Operatoren oder Funktionsaufrufen. Liefert einen Wert. Aufzählungstyp (enumeration type) ist ein Datentyp, dessen Wertebereich vollständig durch die Aufzählung der Einzelelemente beschrieben wird. Durch die Reihenfolge der Aufzählung wird eine Ordnungsrelation definiert. average case ist eine Betrachtungsweise bei der Komplexitätsanalyse von Algorithmen, die sich am Erwartungswert des Betriebsmittelverbrauchs bei der Ausführung eines Algorithmus orientiert. Baum ist eine nichtlineare Datenstruktur, die aus einer Menge von Knoten und aus einer Menge von diese verbindenden, gerichteten Kanten besteht. Bäume werden hauptsächlich zur Abbildung hierarchischer Beziehungen innerhalb großer Datenmengen oder zur Modellierung rekursiver Objektstrukturen verwendet. Benutzerdefinierter Typ (user defined type) Typ, der als Klasse, Aufzählungstyp oder durch eine Typdeklaration eingeführt wird. Bezeichner (identifier) Name der sich auf eine Variable, einen Typ oder eine Funktion bezieht. Block eine Liste von Anweisungen, die den Gültigkeitsbereich aller lokal definierten Bezeichner begrenzt. binärer Baum ist ein spezieller k-närer Baum (siehe dort), der Ordnung 2. Jeder Knoten mit Ausnahme der Blätter besitzt höchstens zwei und mindestens einen Nachfolger. Da jeder k-näre Baum in einen binären Baum durch Anwendung geeigneter Transformationsregeln überführt werden kann, werden hier hauptsächlich Darstellungsformen und Operationen für binäre Bäume behandelt. binäre Suche ist eine Art der Suche, bei der ein nach dem Primärschlüssel aufsteigend oder absteigend sortierter Datenbestand sukzessive in zwei Hälften aufgeteilt wird. Das jeweils mittlere Element der aktuellen Bestandshälfte wird mit dem Suchschlüssel verglichen, das Ergebnis dieses Vergleichs gibt an, ob in der vom mittleren Element ausgehenden linken oder rechten Bestandshälfte weitergesucht wird. 81 IK_1_Datenstrukturen.fm Seite 82 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen BOOLEAN Aufzählungstyp, dessen Wertebereich ausschließlich aus den Wahrheitswerten FALSE und TRUE besteht. Bubblesort ist das Sortieren durch Austauschen. CHAR Datentyp, dessen Wertebereich den im Rechner darstellbaren Zeichenvorrat umfasst (z.B. ASCII-Code). DATA Schlüsselwort bei der Formulierung von Algorithmen, das den Beginn des Datenobjektteils anzeigt. Datenstruktur ist die einfache bzw. komplexe verschachtelte Anordnung von Datenobjekten. Datentyp ist eine Zusammenfassung von Datenobjekten gleicher Art und dazugehörigen Operationen zu einer begrifflichen Einheit, die es ermöglicht, Objekte als Vertreter einer bestimmten Objektmenge zu identifizieren, untereinander zu unterscheiden und Manipulationen für die „Klasse“ von Objekten zu formulieren. Graph ist eine nichtlineare Datenstruktur aus Knoten und Kanten. Die Kanten eines Graphen können sowohl ungerichtet (ungerichteter Graph) als auch gerichtet (gerichteter Graph) sein. Bäume können und werden meistens als spezielle gerichtete Graphen aufgefasst. Im Unterschied zu Bäumen können zwei Knoten eines Graphen auch durch mehrere verschiedene Kantenfolgen verbunden sein. Hashfunktion ist eine Funktion, die aus einem Primärschlüssel die (relative) Adresse berechnet, an der ein Datensatz auf einem direkt adressierbaren Speichermedium abgelegt werden soll. Bei der direkten Adressierung ist die Hashfunktion umkehrbar eindeutig, d.h., es gibt zu jedem Primärschlüssel genau eine Adresse und umgekehrt. Bei der indirekten Adressierung können mehrere unterschiedliche Primärschlüssel auf die gleiche Adresse abgebildet werden, es ist daher eine Kollisionsbehandlung erforderlich. Heapsort ist ein Sortierverfahren, das sich die Effizienzvorteile von Binärbäumen bei Vergleichs- und Suchoperationen in großen Datenbeständen zu eigen macht. Die zu sortierende Objektmenge wird in ein Feld (Array) übertragen, das als ein Binärbaum in schichtenweiser Darstellung mit niveauweiser Nummerierung angesehen wird. Anschließend werden, ausgehend von den Blättern, die Elemente so vertauscht, dass die Wurzel eines jeden Teilbaums, jeweils den Datensatz mit dem größten Schlüssel enthält. Der Heapsort weist ein günstiges Verhalten im worst case auf. Heterogener zusammengesetzter Typ ist ein zusammengesetzter Datentyp mit Elementen von möglicherweise unterschiedlichen Typen, z.B. eine Klasse. Homogener zusammengesetzter Typ ist ein zusammengesetzter Datentyp mit lauter Elementen vom gleichen Typ, z.B. ein Array. Invariante ist ein logischer Ausdruck, der immer gültig ist, z.B. eine Schleifeninvariante (bei jedem Schleifendurchlauf gültig) oder Klasseninvariante (vor und nach jedem Methodenaufruf gültig). 82 IK_1_Datenstrukturen.fm Seite 83 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen k-närer Baum ist ein Baum, für den gilt: Von jedem Knoten außer einem Blattknoten gehen maximal k Kanten aus, jeder Knoten besitzt damit höchstens k Söhne. Der Parameter k heißt auch Ordnung des Baumes. Von einem geordneten k-nären Baum spricht man, wenn die Knoten in einer bestimmten, eindeutigen Reihenfolge notiert oder bezeichnet werden (z.B. alfabetisch, Väter vor Söhnen, Söhne vor Brüdern). Kante ist die gerichtete oder ungerichtete Verbindung zwischen genau zwei Datenobjekten oder Knoten einer nichtlinearen Datenstruktur. Diese Verbindung kann z.B. hierarchische Beziehungen, Transformationen, die Anwendung von Operatoren oder Zustandsübergänge zwischen den Knoten zum Ausdruck bringen. Ist ein Knoten k von einem Knoten v aus über eine zusammenhängende Folge von Kanten zu erreichen, so bezeichnet man den Knoten v auch als (ggf. mittelbaren) Vorgänger von Knoten k und umgekehrt Knoten k als (ggf. mittelbaren) Nachfolger von Knoten v. In Bäumen stellen Kanten gerichtete Vater-Sohn-Beziehungen dar. Knoten sind Elemente eines Graphen oder Baumes, die aus Datenobjekten beliebiger Komplexität zusammengesetzt sein können. Die in einzelnen Knoten oder in mehreren durch Kanten verbundenen Knoten abgelegte Information beschreibt Prozesse, Sachverhalte oder (hierarchische) Zusammenhänge aus der realen Welt. Kontrollstruktur ist ein schachtelbares Sprachmittel zum Modifizieren der normalen, linearen Abwicklung von Anweisungen (z.B. Verzweigungen, Schleifen usw.). Implementierung ist die Übersetzung der erarbeiteten Datenmodelle und Datenverarbeitungsprozesse in eine von einem Computer ausführbare Form und deren Einbindung in die bereits bestehende Informationsstruktur. INTEGER ist ein Standarddatentyp, der den computerintern darstellbaren Ausschnitt aus der Menge der ganzen Zahlen angibt. Komplexität von Algorithmen beschreibt Speicherplatzbedarf und die Laufzeit in Abhängigkeit von der eingegebenen Problemgröße n. Da das Verhalten des Algorithmus bei wachsender Problemgröße n meist nicht präzise angegeben werden kann, wird versucht, das Wachstumsverhalten auf eine bekannte Funktion g(n) zurückzuführen. Die so genannte O-Notation f(n) = O(g(n)) bringt zum Ausdruck, dass durch g(n) eine obere Grenze für die Anzahl der nötigen Elementaroperationen f(n) bei wachsender Problemgröße angegeben wird. Notation von Algorithmen ist die Darstellung von Algorithmen in verbaler, quasiformaler oder grafischer Form. Gebräuchliche Notationsformen sind Pseudocode, Struktogramme und Flussdiagramme. Nach BÖHM und JACOPINI gibt es für jeden Algorithmus eine äquivalente Darstellung, die mit den Strukturblöcken Sequenz, Wiederholung und Verzweigung auskommt. Nachfolger heißt ein Knoten n, wenn dieser von einem Knoten k aus über eine zusammenhängende Folge von q Kanten zu erreichen ist, falls q = 1. Er wird als mittelbarer Nachfolger von k bezeichnet, falls q > 1 ist. Die Nachfolger eines Knotens werden auch als Söhne dieses Knoten bezeichnet. 83 IK_1_Datenstrukturen.fm Seite 84 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Notation ist eine bestimmte Darstellungsform von Information durch Symbole, wie zum Beispiel zum Aufzeichnen von Noten, von Schachpartien oder von mathematischen Modellen. Die Notation einer Programmiersprache bestimmt die zulässigen Sprachelemente, wie z.B.: Konstante, Ausdrücke und Anweisungen und teilweise die Syntax. Quicksort Sortierverfahren, das auf den Prinzipien Austauschen und Zerlegen beruht. Rekursion ist die Definition einer Datenstruktur, eines Verfahrens (Algorithmus) oder einer (mathematischen) Funktion durch sich selbst. Eine rekursive Verfahrensvorschrift besteht in der Regel aus einer Terminationsbedingung, einer optionalen Ausführungsanweisung und einem Selbstaufruf. Die wohl bekannteste rekursiv formulierte Funktion ist folgende Vorschrift zur Fakultätsberechnung: n! = n ((n – 1)!) mit der Terminationsbedingung 0! = 1. Sortieren ist die Umordnung einer Menge von Objekten oder Datensätzen so, dass die Objekte entsprechend einer Ordnungsrelation (numerisch, lexikografisch) aufoder absteigend angeordnet sind. Befindet sich der zu sortierende Datenbestand zum Zeitpunkt des Umordnens vollständig im Hauptspeicher, so spricht man von einem internen Sortierverfahren, andernfalls von einem externen Sortierverfahren. Suche ist das Auffinden eines oder aller Datenobjekte in einem Datenbestand, die ein bestimmtes Suchkriterium erfüllen. Die Effizienz der Suche wird von der Art des Suchkriteriums (einfacher oder zusammengesetzter Schlüssel), dem benutzten Suchverfahren und von der Organisation des Datenbestandes bestimmt. Suchbaum ist eine nichtlineare Datenstruktur, in der durch Schlüssel identifizierte Datenobjekte auf effiziente Weise ordnungserhaltend eingefügt und gefunden werden können. Über die Menge aller vorhandenen Schlüssel muss eine lineare Ordnungsrelation (größer, gleich oder kleiner) definiert sein. Suchbäume werden meist als Binärbäume dargestellt, in denen jeder Knoten einen einzigen Schlüsseleintrag s enthält. Bei der Suche nach einem eindeutigen Schlüssel x wird in jedem Knoten des Suchbaumes zum linken Nachfolger verzweigt, wenn x kleiner ist als der Schlüsseleintrag s im aktuell betrachteten Knoten, und nach rechts verzweigt, wenn x größer ist als s. Die Komplexität der Schlüsselvergleiche ist damit durch O(ld n) gegeben. Um die Sortierfolge aller Datenobjekte zu erhalten, ist der Suchbaum lediglich in symmetrischer Ordnung zu traversieren (inorder). Traversieren von Bäumen: Da man bei den gebräuchlichen Darstellungs- und Speicherungsformen für Bäume auf einzelne Knoten nur indirekt, von der Wurzel aus, zugreifen kann, ist es nötig, einen Baum in einer bestimmten Reihenfolge so zu durchlaufen, dass jeder Knoten genau einmal aufgesucht und ausgewertet wird. Normalerweise werden drei verschiedene Vorgehensweisen für das Durchlaufen eines Binärbaumes in Betracht gezogen: das Traversieren in Präordnung, in Postordung und in symmetrischer Ordnung. Allen Vorgehensweisen ist gemeinsam, dass der Binärbaum in jedem Knoten k in drei Elemente aufgeteilt wird: den von k ausgehenden rechten Teilbaum, die Wurzel k und den von k ausgehenden linken Teilbaum. Damit lassen sich Traversierungsalgorithmen relativ leicht rekursiv formulieren, indem die Reihenfolge des Abarbeitens der genannten drei Elemente festgelegt wird. 84 IK_1_Datenstrukturen.fm Seite 85 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen REAL ist ein Datentyp, der die im Rechner darstellbare Teilmenge der reellen Zahlen angibt. Record (Verbund, Satz) ist die Zusammenfassung von mehreren, auch unterschiedlichen Datentypen zu einem neuen Datentyp. Die einzelnen Komponenten des Verbunds können mit Hilfe der Punktqualifizierung angesprochen werden (z.B. person.name). Schlange (engl. queue) ist eine lineare Datenstruktur, mit der eine Folge von Datenobjekten eines bestimmten Datentyps nach dem „first-in-first-out“-Prinzip verwaltet wird. Neu hinzu kommende Elemente werden stets am Ende der Folge angefügt (Operation append). Entfernt werden Elemente ausschließlich am Anfang der Folge (Operation remove). Die Schlange lässt sich wie der Stapel als sequentielle oder als verkettete Liste organisieren. Set oder Mengentyp ist ein Datentyp, der eine Menge von Objekten im Sinne der Mengenlehre nachbildet. Die Elemente der Menge gehören alle einem einfachen ordinalen Datentyp an. Stack (Stapel) ist eine lineare Datenstruktur, bei der eine Folge von Datenobjekten eines bestimmten Datentyps nach dem „last-in-first-out“-Prinzip verwaltet wird. Für den Stapel gibt es in der Regel zwei grundlegende Operationen: Die Operation push fügt neu hinzukommende Elemente stets am Ende der Folge an, die Operation pop liefert das letzte in die Folge aufgenommene Element. Stapel können als sequentielle Liste (statisches Feld) oder als verkettete Liste realisiert werden. Standardtypen sind elementare Datentypen, die in den meisten (höheren) Programmiersprachen zur Verfügung gestellt werden. Hierzu gehören die Datentypen INTEGER, REAL, CHAR und BOOLEAN. Typ (type) Interpretation eines Bitmusters als Wert. Festlegung erlaubter Operationen und der Auswirkungen dieser Operationen auf die Werte, d.h. Exemplare des Typs. Typdeklaration (typedef) Neuer Bezeichner für einen anderen einfachen oder zusammengesetzten Typ. Verkettete Liste ist eine Folge von Datenobjekten eines bestimmten Datentyps, bei der jedes Datenobjekt aus einem Datenteil und einem Verweisteil besteht. Da im Gegensatz zur sequentiellen Liste die physikalische Aufeinanderfolge der Elemente nicht mit der logischen Reihenfolge, die der zugrundegelegten Ordnungsrelation entspricht, übereinstimmt, ist eine Verzeigerung der Datenobjekte einzurichten: Ein zusätzliches, als Anker bezeichnetes Datenobjekt, verweist auf das erste Listenelement. In diesem sowie in jedem weiteren Element wird ein Verweis auf das Nachfolgerelement festgehalten. Der Zeiger des letzten Elements markiert das Ende der Liste (NIL). Werden in jedem Listenelement mehrere Verweise gepflegt, spricht man von doppelt oder mehrfach verketteten Listen. 85 IK_1_Datenstrukturen.fm Seite 86 Montag, 30. Dezember 2002 10:35 10 IK 1 Algorithmen & Datenstrukturen Zeichenkette (String) ist eine Zusammenhängende Folge von Zeichen aus einem endlichen Zeichenvorrat, die ein Phänomen der realen Welt repräsentiert. Im Rechner werden Zeichenketten in einem Array abgelegt; das Ende einer Zeichenkette wird in der Regel durch ein Sonderzeichen bestimmt. Zeigertyp ist ein Datentyp, der einen Verweis (Zeiger, auf der Rechnerebene Adresse) auf ein Datenobjekt eines zugrunde gelegten Datentyps beschreibt. Der Wertebereich des Zeigers umfasst hierbei die möglichen Speicheradressen und den Wert NIL. Ein Zeiger mit dem Wert NIL verweist auf kein Datenobjekt. Zusammengesetzter Typ („compound type“) Typ, der aus Elementen zusammengesetzt ist. Gegenteil von primitivem Typ. Vorgänger eines Knotens: Ist ein Knoten k von einem Knoten v aus über eine zusammenhängende Folge von q Kanten zu erreichen, so bezeichnet man den Knoten v als Vorgänger des Knotens k, falls q = 1, und als mittelbaren Vorgänger von k, falls q > 1. Ein Vorgänger eines Knotens k wird auch als Vater von k bezeichnet. Wurzel ist ein Datenobjekt oder Element eines Teilbaumes, zu dem kein Vorgänger existiert. Von der Wurzel des Baumes aus können alle Knoten eines Baumes auf genau einem Weg (d.h. einer zusammenhängenden endlichen Folge gerichteter Kanten) erreicht werden. 86