Skript zur Vorbereitung auf die Nebenfachs-Informatikprüfung bei Prof. Schweiggert Stoff: VL Allg. Inf.I + II (mit Wiwis, etc., 2005/2006 VL bei Murmann) Das folgende Skript hab ich zwei Tage vor meiner Prüfung als kleine Zusammenfassung und Übung für mich selbst geschrieben. Deshalb ist das Skript auch nicht perfekt, sachliche Fehler sind möglich und wahrscheinlich, neben Rechtschreibfehlern und schlechtem Satzbau….. aber das wird euch wahrscheinlich herzlich egal sein : ) wenn ihr das könnt, was im skript steht, dann steht der 1,0 nichts mehr im Wege. Viel Erfolg damit, SirTobi Thematik: Sortierverfahren: Sortierung von Daten ist sehr wichtig und beansprucht etwa 25% der Rechnerzeit. Man beschränkt sich dabei immer auf Sortierung von Zahlen durch Größenvergleiche, da sich auch andere Datensätze als reine Zahlen indir. dadurch ausdrücken lassen. Generell wird unterschieden zwischen internem und externem Sortieren. Beim internen liegen alle Datensätze wie in einem Array zu jedem Zeitpunkt zugreifbar zur Verfügung. Es kann theoretisch mit jedem Feld begonnen werden. Externes kann man sich als Sortieren mit Hilfe von Stacks vorstellen, bei denen nur immer jeweils das oberste Element sichtbar ist, und vom Stapel genommen werden kann. Es existieren einige verschiedene Sortieralgorithmen die rein iterativ oder auch rekursiv funktionieren. Je nach Anwendung eignet sich mal der eine, mal der andere Algorithmus besser. Zuerst zu den rekursiven. Sie sind daher rekursiv da die zu sortierenden Datensätze immer auch ein bestimmte Art und Weise durch die gleiche Funktion aufgeteilt und die selben Befehle auf en Teildatensatz neu angewandt werden, es sind endliche Rekursionstiefen möglich. Hier gibt es Quicksort, Mergesort und Heapsort. Es gilt, dass alle Sortierverfahren (auch sämtliche iterativen), bis auf Mergesort, in-Place/in-situ arbeiten. Das bedeutet, dass während des Sortiervorgangs kein weiterer Speicherplatz benötigt wird als die Datensätze einnehmen. Die rekursiven Verfahren besitzen alle im Regelfall nach Landau-Notation die Zeitkomplexität O(nlogn). Kurz zur Landau Notation: sie gibt an wie viel relative Rechenzeit für einen Algorithmus/Funktion/Prozedur benötigt wird. Sie kann Konstant sein, Logarithmisch, Linear, Polynomial und Exponentiell. Quicksort benötigt im schlechtesten Fall O(n²). Es beruht auf dem Divide-et-Impera / Command-and-Conquer Ansatz, nach dem ein Teilproblem immer weiter aufgeteilt wird, bis die Teillösungen trivial sind und wieder zusammengesetzt werden können. Als Pivot-Element wäre der echte Median die beste Wahl, dies ist aber nur in schon sortierten Listen möglich, folglich muss eine Alternative gewählt werden. Die Wahl des ersten Elements garantiert die Termination, erhöht aber die Worst-Case Wahrscheinlichkeit. Das letzte Element endet in einer Endlosschleife wenn es das größte Element im Array ist. Ein gute Wahl ist der Median aus erstem, mittlerem und letztem Element. Die Hilfsvariablen i und j setzen jeweils von links und rechts außen am Array an. i wandert solange nach rechts bis es ein Element größer oder gleich dem Pivot entdeckt. j nach links, bis es eines kleiner oder gleich dem Pivot entdeckt. Dann erfolgt der Austausch dieser beiden Elemente. I und j bewegen sich nach dem gleichen Prinzip weiter bis sie zusammentreffen und i >= j, bzw. i und j auf einem Element sitzen. Dort wird dann das Array in zwei Teile aufgeteilt, also entweder genau zwischen i und j oder rechts davon, wenn sie aufeinander liegen. So wird nun mit den Teildatensätzen weiter verfahren, bis alle Daten geordnet sind und sie zusammengefügt werden können. Quicksort arbeitet nicht stabil, d.h. Datensätze mit gleich großem Schlüsselelement können vertauscht werden. Dies ist problematisch, wenn nacheinander nach mehreren verschiedenen Schlüsseln sortiert wird. Instabil sind außerdem Heapsort und Selectionsort. Die restlichen Algorithmen sind alle stabil. Heapsort (in-Place/ O(nlogn)/ Instabil) basiert auf einem als Binär-Baum (Heap/Halde) behandelten Array. Die Indizes des Array werden so in einen Baum übertragen, dass das Element i die Kinder 2i und 2i +1 besitzt. Die Wurzel ist also das Feld mit Index 1, dessen Kinder 2 und 3, usw. es werden also nach Level-Order von links nach rechts die Daten in den Baum übertragen. Man beginnt nun mit dem Teilbaum, der den höchstwertigen Index besitzt, also „den zuletzt gefüllten“, und vertauscht den Elternknoten, falls der Schlüsselwert kleiner ist als eines oder beide seiner Kinder, mit dem größeren der Kinder. So fährt man fort und geht die Indizes rückwärts bis zu Index 1 (Wurzel). Man muss dabei allerdings darauf achten den Baum immer wieder zu aktualisieren, d.h. wenn ganz oben etwas vertauscht wird, dies sich auch auf schon einmal geordnete Knoten auswirken kann. Dieses Ordnen bewirkt ein Versickern der kleineren Werte nach unten. Ist der Heap fertig geordnet, wird damit begonnen die Wurzel mit dem größten Index zu tauschen und diesen letzen Knoten zu löschen und den Inhalt in jenem Indexfeld zu speichern. (Größter Indexwert: größter Schlüsselwert). Danach muss der Baum durch versickern, so wie vorher, wieder geordnet werden. Dann wird der nächst kleinere Indexknoten entfernt und so fortgefahren bis der Array komplett geordnet ist. Mergesort (nicht in-Place, Stabil, O(nlogn) zeichnet sich durch eine durchgehend gleich bleibende Zeitkomplexität aus und ist gut zum Ordnen verketteter Listen geeignet. Es läuft ebenso nach dem Divide-and-Conquer Prinzip ab und ist stabil. Dabei wird der Array immer weiter aufgeteilt bis ein-feldige Elemente vorliegen, die als geordnet gelten. Die Einzelfelder werden nun entsprechend ihrer Schlüsselwertgrößen Stück für Stück auf demselben Weg rückwärts zusammengesetzt. Es entsteht ein geordneter Array. Nachteilig ist allerdings der zusätzlich notwendige Speicherplatz zur Zwischenspeicherung. Soviel zu den rekursiven und wohl auch grundsätzlich interessanteren Sortiermethoden. Bei den iterativen gibt es Selectionsort, Insertionsort und seine Weiterentwicklung Shellsort, Bubblesort und den bidirektionalen Bubblesort, auch Shakersort genannt. Omikron beläuft sich immer auf O(n²) außer bei Shellsort, welches eine geringere Zeitkomplexität von ca. n 1,25 besitzt. Selectionsort (instabil, O(n²), in-Place) durchläuft das Array linear und sucht das kleinste Element, welches dann mit dem Element auf Indexfeld 1 vertauscht wird. Dann sucht es das zweitgrößte, welches auf Feld 2 kommt, usw.. Insertionsort (stabil, O(n²), in-Place) durchläuft das Array, sucht das Kleinste Schlüsselelement und schiebt es an die Stelle des ersten Feldes. Die nachfolgenden Felder bis zum gewählten Feld, müssen also alle um eines verschoben werden. Dann das zweitkleinste an die zweite Stelle, wiederum verschieben des Restes, usw.. Eine Weiterentwicklung ist Shellsort (in-Place/Stabil/O(n1,25). Dabei wird eine ungeordnete Sequenz in eine zweidim. Matrix übertragen, die nun Spaltenweise mittels Insertionsort geordnet wird. Dann wird die Matrix in eine weitere Matrix übertragen die kürzere Zeilenlänge aufweist. Deren Spalten werden auf ein Neues mit Insertionsort geordnet. Am Schluss liegt wieder eine eindimensionale Sequenz vor, die ein letztes Mal mit Insertionsort geordnet wird. Von den iterativen Sortiermethoden ist dies die schnellste (siehe oben) obwohl der mathematische Beweis schwierig ausfällt. Bubblesort (stabil/in-place/O(n²) ist ein recht naiver Algorithmus der selten benutzt wird. Er basiert auf paarweisem Vergleich von Schlüsselwerten im Array, bei dem die Elemente so vertauscht werden, dass die schwereren (höherwertigeren) Elemente nach rechts blubbern, bis es auf ein größeres Element stößt, welches dann weiter nach rechts verblubbert wird. Eine weitere Möglichkeit ist Shakersort, bzw. der bidirektionale Bubblesort. Der erste Schritt ist wie bei Bubblesort. Ist man dann am rechten Rand angekommen geht man von dort nach links, wobei man nun die kleinsten Elemete nach der äquivalenten Regel nach links vertauscht. So wandert man nun hin und her bis der Array geordnet ist. Ein Geschwindigkeitsvergleich ergibt, dass Shellsort schneller als die anderen iterativen Algorithmen läuft. Bei unsortierten sowie vorsortierten Daten (was im Rechner viel häufiger vorkommt/nur leichte Veränderungen im Datensatz) zeigt sich folgende Reihenfolge, beginnend mit dem Schnellsten: Quicksort, Mergesort, Heapsort Bei unsortierten Datensätzen ist Bubblesort von den iterativen der langsamste, allerdings bei vorsortierten Sätzen der Schnellste (abgesehen von Shellsort). Thematik Bäume: Bäume sind eine wichtige Struktur in der Informatik um Daten zu organisieren, zu speichern und wieder zu finden. Es existieren mehre Definitionen. -Bäume sind spezielle, gerichtete, zusammenhängende Graphen. -Rekursive Def.: Ein Baum ist leer oder hat einen Wurzel die mit weiteren disjunkten (nicht gleichen, nicht überschneidenden) Bäumen über Kanten verbunden ist. Weitere Eigenschaften eines Baumes: -jeder Knoten hat nur eine eingehende Kante, es sind keien Zyklen erlaubt, Höhenbalanciertheit: Die Pfadlänge (von Wurzel zu beliebigem Blatt) innerhalb eines Baumes darf sich nicht um mehr als 1 (oder je nach gewähltem Wert) unterscheiden. Gewichtsbalanciertheit (auch vollständig balanciert genannt): Die Anzahl der Kinder eines Knotens differiert um nicht mehr als 1 vom Grad des Baumes. Der Grad bezeichnet die Anzahl der Kinder die ein Knoten hat. So ist ein Binärbaum vom Grad zwei. Die Höhe hat in der Wurzel den Wert 0, und nimmt in jeder Generation um eins zu. Die Anzahl der inneren Konten eines Binärbaums lässt sich mit der Formel 2h-2 berechnen, die Anzahl der Blätter mit 2h. Bei einem geordneten Baum sind die in den Knoten und Blättern gespeicherten Werte nach der Größe geordnet. Bei einem orientierten Baum nicht (Darstellung durch geschachtelte Mengen möglich). Bäume werden zur Datenorganisation z.B. auch in Betriebssystemen eingesetzt, so ist das Dateisystem von Unix ein Vielwegbaum. Weiterhin ist auch der Ascii-Code als Baum festgelegt in dem nur die Blätter die Informationen/die Ascii-Symbole tragen und die Knoten nur den Weg über 0 und 1 weisen. Dies entspricht einem Blattsuchbaum. Auch spielen bei der Datenkomprimierung etwa von Textdateien Bäume eine Rolle. Man nutzt dabei HuffmanBäume in denen die Buchstaben eines Alphabets der Wahrscheinlichkeit ihres Vorkommens nach in den Knoten und Blättern gespeichert sind. Es gibt verschiedene Weisen/Notationen einen Baum mit Daten zu füllen, bzw. sie auszulesen/ zu traversieren. Infix: links, Wurzel, rechts Präfix: Wurzel, links, rechts Postfix: links, rechts, Wurzel, Diese Weisen sind rekursiv zu verstehen und werden bei Traversierung nicht mit –fix sondern mit -order benannt. Postorder ist von Maschinen leichter zu verarbeiten. Der Shunting-Yard-Algorithmus kann Infix-Notationen in Postfix umwandeln (läuft über Stack). Nun einige Modula 2/programmierrelevante Informationen. Bäume können als ADT aufgefasst werden. Die übliche Implementation läuft über Zeiger: TYPE pBaum = POINTER TO Baum Baum = RECORD key : INTEGER; left, right: pBaum; END; Eine Prozedur die alle Knoten eines Baums zählt könnte folgendermaßen aussehen: PROCEDURE zaehlen (b: pBaum; VAR zaehler: CARDINAL) BEGIN IF b <> NIL THEN zaehlen (b^.left, zaehler); zaehlen (b^.right, zaehler); INC (zaehler); END zaehlen; Aufruf durch: Y:=0; Zaehlen (x,y); C:=Y ( hier ist dann der zaehlerwert drin) Oder auch: PROCEDURE visit (b: pBaum; VAR: zaehler: INTEGER); BEGIN visit (b^.left); zaehler := zaehler + 1; visit (b^.right); END visit; Auslesen würde genauso funktionieren: Reihenfolge kann als In-Order, Pre-Order oder PostOrder gewählt werden. PROCEDURE traversiere (b: pBaum); BEGIN IF b <> NIL THEN In-Order: Traversiere (b^.left); WriteInt (b^.key); traversiere (b^.right); Pre-Order: WriteInt (b^.key); traversiere (b^.left); traversiere (b^.right); Post-Order: traversiere (b^.left); traversiere (b^.right); WriteInt (b^.key); END traversiere; Suchen eines bestimmten Elementes w im Baum: PROCEDURE suche (w:INTEGER; b: pBaum): BOOLEAN BEGIN IF b =NIL THEN RETURN FALSE IF w = b^.key THEN RETURN TRUE; ELSIF w < b^.key THEN RETURN suche(w, b^.left); ELSE RETURN suche (w,b^.right); END suche; Eine Prozedur die einen Binärbaum auf Vollständigkeit überprüft kann mittels zweier Prozeduren realisiert werden. PROCEDURE count (b:pBaum) : INTEGER BEGIN IF b=0 THEN RETURN 0 ELSE RETURN 1 + count(b^.left) + count(b^.right); END; END count; PROCEDURE test(b:pBaum): BOOLEAN BEGIN RETURN count(b^.left)=count(b^.right); END test; ADT Stack und Queue: Da sie ADTs sind, sind sie implementierungsunabhängig. Es ist also für den Benutzer nicht von Belang, ob sie über spezielle Arrays oder über Zeiger erstellt werden. Stack: Hier greift das Prinzip: Last In, First Out. LIFO. Man nennt Stacks auch Stapel, bzw. Kellerspeicher. Die zentralen Operationen in einem Stack sind: Stack leer?, Stack voll?, push, pop, top. Queue: First In, First Out, FIFO Zentrale Operationen: Queue leer?, Queue voll? Push am Ende, Pop am Anfang, Meist wird eine Implementierung über verkettete Listen gewählt. Diese können einfach oder doppelt verkettet sein.+- Zählen der Listenelemente, einfach verkettet: PROCEDURE zaehlliste (l:link): INTEGER BEGIN IF l = NIL THEN RETURN 0 ELSE RETURN 1 + zaehlliste(l^.next); END END zaehlliste; C := zaehlliste (b); Rekursive Prozedur zum Anhängen von Elementen hinten an der Liste: PROCEDURE enqeueue (zahl: INTEGER; VAR liste: pListe ); BEGIN IF liste = NIL THEN liste^.key := zahl; liste^.next := NIL; ELSE enqueue (zahl, liste^.next); END END enqueue; Einfügen Vorne in Liste PROCEDURE vorne (zahl: INTEGER; kopf: link) VAR p: link BEGIN P^.key := zahl; P^.next := kopf; Kopf := p; END vorne; Doppelt verkettete Listen sind geeignet für Datensequenzen, die von beiden Seiten gelesen werden können sollen. (4 verben am ende eines satzes, das gibt’s nur im deutschen ) So wie z.B. lange Zahlen. Hashing: Hash-tabellen werden erstellt wenn Datenbanken geschaffen werden sollen. Dabei ist die Zeitkomplexität im Idealfall O(1). Einer Reihe von Datensätzen wird durch eine Hash-Funktion ein bestimmter Platz in einem Array zugewiesen. Die Funktion wird benötigt wenn die Daten darauf verteilt werden und wenn sie beim Zugriff wieder gefunden werden müssen. Die Daten werden auf dem Array gestreut, in gewisser Weise zufällig zueinander. Bei der Reservierung des Speicherplatzes sollte beachtet werden, dass die Tabelle platzmäßig nur zu 80% mit allen Daten gefüllt ist. Eine Hash-Funktion liefert im Idealfall keine Kollisionen. Um dem zu entgegnen, gibt es zwei Stragtegien die dies verhindern. Einerseits besteht die Möglichkeit den Array mit Zeigern zu füllen, die im Fall einer Kollosion einfach den zusätzlichen Datensatz an den jeweiligen Zeiger anhängen und somit eine Liste entsteht. Die andere Möglichkeit ist lineare Sondierung zu benutzen, wobei bei einem durch die Hash-Funktion zugewiesenen aber belegten Speicherplatz einfach im Array abwärts gerutscht wird, bis ein freies Feld entdeckt wird, welches dann gefüllt wird. Beim Hashing kann eine theoretisch unendliche Quellmenge auf den Wertebereich der Hashfunktion reduziert werden. Die Hashfunktion sollte einfach zu berechnen sein und trotzdem möglichst keine Kollisionen erzeugen. Mustersuche Wenn man in einem Text ein Wort, also eine bestimmte Abfolge von Buchstaben finden will kann einfach linear die Sequenz durchgehen und solange nach der Abfolge suchen bis sie entdeckt wurde (Brute-Force-Ansatz). Falls aber Teile des Wortes schon vorkommen kann man die Informationen dieses Mismatch nutzen, mitzählen und dann die entsprechenden Abstände weiterspringen (Knuth-Morris-Pratt-Algorithmus). Dateien in UNIX Unter Unix gibt es drei zu unterscheidende Dateitypen. Es gibt: Reguläre Dateien: Binäre Daten, Texte, Software, etc. Dateiverzeichnisse/Katalogdateien: enthalten Inode-Listen, Verweise auf Speicherort Spezielle Dateien/Gerätedateien: sind zuständig für Einbindung der Hardware, stehen für die Geräte Inode: Index-Node: 128 byte große spezielle Datenstruktur die einer Datei zugehörig ist und Daten über diese Datei enthält Speichert Typ, Größe, Datum, Besitzer, Zugriffsrechte, etc., sowie Verweise auf die Cluster in Speicher wo sich eigentliche Datei befindet. Kleine Dateien können direkt in der Inode gespeichert werden, sehr große enthalten in ihren ersten Clustern nochmals Verweise auf weitere Cluster. Sprache In einer Sprache existieren Zeichen, die Elemente eines Alphabets sind. Ihre Aneinandereihung zu Worten und Sätzen wird durch die Syntax geregelt. Die Interpretation und Wirkung der Zeichenfolgen, z.B. durch einen Rechner wird durch die Semantik übernommen. Die Grammatik ist ein 4-er Tupel, welches Produktionsregeln, Terminalzeichen, Nichtterminalzeichen und das Startsymbol enthält. EBNF (Erweiterte-Backus-Naur-Form) ist eine Metasprache, mit der man die Produktionsregeln vereinfacht und nach bestimmten Regeln darstellen kann. Sie benutzt zur Gliederung und Darstellung von Möglichkeiten die Symbole [ ]. Option, {} Null bis beliebig oft, | oder, ( ) Klammerung. Der Komplexitätsgrad einer Sprache wird durch die Chomsky-Hierarchie angegeben. Sie werden von verschiedenen Automaten erkannt. Typ 0: Grammatik ohne Einschränkungen, Turingmaschine, Typ 1: mit Einschränkungen, abgewandelt Turingm. Typ 2: kontextfrei, Kellerautomat, sind durch EBNF darstellbar Typ 3: reguläre Gram., DEA, sind durch EBNF darstellbar Ein Wort ist Teil der Sprache, wenn damit ein Terminalzustand erreicht wird. Ist Wort Teil der Sprache? (bottom up, Top down) Ein regulärer Ausdruck ist eine Terminalzeichenfolge die von einem Automat erkannt wird. Bei Textersetzungen, Suchen in Editoren. Die Befehle in UNIX können gemeinsam mit regulären Ausdrücken vorkommen. Jede durch einen endlichen Automaten erkannte Sprache ist regulär. Datentypen Es wird zwischen drei großen Datentypengruppen unterschieden. Einerseits einfache Datentypen (Gleitkommazahlen, Boolean, Interger, Char, Enumeration, Subrange,etc.), strukturierte Datentypen (Arrays, Record, Sets) und dynamische Datentypen (Zeiger). Einfach Datentypen: Boolean: belegt ein Bit, hat keinen Wertebereich, nimmt nur TRUE oder FALSE an, Operatoren sind NOT, AND, OR (in der Mächtigkeit der Abfolge), es sind die üblichen Vergleiche möglich. Char: Darstellung von Zeichen im Rechner, basiert auf ASCII (american standard code for information interchange), ASCII hat 7 bit (es gibt abwandlungen mit 8 bit um alle Sonderzeichen einer Landessprache auszudrücken). Das 8 Bit wurde auch genutzt um zu überprüfen ob die Gesamtfolge der Bits eine gerade Zahl ergibt, um die Fehlerquote bei Datenübertragungen im Auge zu behalten. Neuerdings findet allerdings ein Umstieg auf Unicode statt, bei dem es auch div. Untertypen gibt. Am gebräuchlichsten ist die Darstellung durch UTF-8 (Unicode Transformation Standard): der von 1 Byte (beinhaltet normalen ASCII) bis zu 6 Byte reicht. Damit können alle Schriftzeichen die es auf der Welt gibt dargestellt werden. Jedem ASCII Symbol ist ein Ordinalwert zugeordnet der durch den Befehl ORD(symbol) erhalten werden kann. Umgekehrt erhält man das ASCII-Symbol nach Eingabe der Ordinals mittels CHR(ASCII-Code). Integer: Wertebereich der ganzzahligen negativen und positven Zahlen, die Untertypen Byte stellen 8bit zur Verfügung, ShortInt 16 bit, Integer standardmäßig 32 bit, und LongInt 64 bit, wobei es immer auf das Rechnersystem ankommt mit dem man arbeitet. Da in einem Rechner nur ein Addierwerk existiert müssen auch Subtraktion dadurch dargestellt werden. Problematisch ist also die rechnerinterne Darstellung negativer Zahlen. Dies wird gelöst durch das Zweier-Komplement. Hierbei wird zunächst eine positive Zahl stellenweise invertiert und ein letztes Bit addiert. Das erste bit stellt dabei sozusagen die negativen –128 dar (bei 8 bit) und die restlichen mit eins besetzten Stellen, die Werte die zur –128 addiert werden müssen. Operationen sind also Addition, Subtraktion, DIV mit Rest, MOD, Multiplikation und Vergleiche. -MAXINT und MAXINT begrenzen den abgedeckten Zahlenbereich. Cardinal: zur Darstellung positiver ganzzahliger Zahlen, gibt es in manchen System schon gar nicht mehr. Übliche Operationen möglich, Real: Gleitkommazahlen die nicht den mathematischen reellen und rationalen Zahlen entsprechen, da der Speicherbereich endlich ist. Folglich ist es nur eine Näherung, deren Genauigkeit von der Größe des Exponenten und er Mantisse abhängig. Shortreal besetzt bei der 32 Bit-Wortlänge, ein Bit mit dem Vorzeichen, 8 Bit mit dem Exponenten und 23 Bits mit der Mantisse. Longreal mit 64 Bit Wortlänge ebenso ein Bit mit dem Vorzeichen, 11 Bit mit dem Exponent und 52 Bit mit der Mantisse. Der Bereich um 0 kann nicht exakt dargestellt werden und wird als 0 interpretiert. Dies kann als Zwischenergebnis zu Problemen führen. (negative und positive Underflow). Bereichsüberschreitungen werden auch bei Integer durch Overflowbit angezeigt. Die Genauigkeit ist im Kleinen groß, und nimmt mit der Größe der Zahl ab (endlicher Speicherbereich). Für arithmetische Berechnung gibt es spezielle Prozessoren. Deren Leistung wird in FLOPS (Floating Point Operations Per Second) angegeben. Also die Anzahl der Additionen oder Multiplikationen die in einer Sekunde bewältigt werden können. Die Einheit MIPS (Million Instructions Per Second) gibt an, wie viele Maschinenbefehle in der Sekunde eingelesen werden können. 1 MIPS bedeutet, er kann eine Million Maschinenbefehle pro Sekunde ausführen. Strukturierte Datentypen: Array: Speichert gleichartige Daten in einem linearen Speicher, mehrdimensionale Arrays enthalten in ihren Feldern ebenfalls weitere Arrays. Je nach Schachtelung viele Dimensionen möglich. Record: Speicherung verschiedenartiger Daten Dynamische Datentypen: Zeiger: Daten werden über anonyme Adressen indirekt angesprochen, er enthält nur einen Verweis (die Adresse) auf die eigentlich Datei. Es gibt keinen Index und die Speicherbereiche müssen nicht zusammenhängend sein. Die Lebensdauer ist unbestimmt.. Bsp. Liste: je nach Aktion wächst oder schrumpft die Liste dynamisch, die einzelnen Zeiger werden alloziert oder dealloziert. Rekursion Rekursion ist ein nicht nur in der Informatik existentes Phänomen. Grundsätzlich ist damit eine Erscheinung gemeint, die immer wieder durch die selben Schritte auf sich bezogen entsteht. Bspw. Ein math. Funktion die sich selbst enthält (z.B. FibonacciReihe: f(n)= f(n-1)+f(n-2)), eine Prozedur die sich selbst aufruft oder Muster die immer wieder auf die Teile des bestehenden Musters gesetzt werden (Fraktale, Pythagorasbaum, Mandelbrotmenge, Küstenlinien, Populationsdynamik Blattinduktion mit Fibonacci, Attraktoren mit Oszillation um Grenzwert, Wasserstrudel, etc.). Auch gibt es rekursive Definitionen (siehe Baumdefinition). Zur Rekursion in der Informatik. Sie spielt dort vor allem eine Rolle bei Prozeduraufrufen. Als dir. Rekursion wird es angesehen, wenn eine Prozedur während ihres Aufrufs sich selbst nochmals aufruft. Indirekte/verschränkte Rekursion nennt man den Zustand bei dem eine Prozedur A eine Prozedur B aufruft, die wiederum A aufruft. Eine einfach rekursive (Funktions-)Prozedur, die die Fakultät einer Zahl ausgibt ist folgende: PROCEDURE fakult (x:INTEGER):INTEGER BEGIN IF x=0 THEN RETURN 1 ELSE RETURN x*fakult(x-1); END fakult; Es ist wichtig bei rekursiven Prozeduren eine Abbruchbedingung mitanzugeben, da sonst die Gefahr von Endlosschleifen droht. Dies wird durch den Trivial/Basis-Fall gehandhabt. Es existieren immer eine Abbruchbedingung und ein Rekursionszweig. Rekursive Implementierungen sind meist eleganter, kürzer und einfacher als iterative Implementierungen. Sie sind aber auch meist etwas langsamer und brauchen mehr Speicher. Es gibt einige Untertypen von Rekursion: Lineare Rekursion: bei der in jedem Zweig höchstens ein Selbstaufruf stattfindet. (fakultät) Eine Lineare Rekursion ist dann eine Repetitive/tail-Rekursion: wenn der Aufruf am Ende erfolgt, kann durch eine Schleife ersetzt werden. Sodass anstatt neuer Inkarnationen, Variablen wiederverwendet werden, dies spart Speicherplatz. Kaskadenartige/baumartige Rekursionen: sie sind nicht linear, und es kommt in den Aufrufzweigen zu mehr als einem Aufruf (Fibonacci). Geschachtelte Rekursion: z.B.: f(n)=f(n+1) oder so... (so, jetzt hab ich keine Lust mehr) Prozeduren Wichtige Stichworte zu Prozeduren: Normale und Funktionsprozeduren, direkter Aufruf, Aufruf als Teil von Ausdruck, Resulttype, Ergebniswert, Call-by-value, Call-by-reference, aktuelle und formale Parameter, Substitution, Seiteneffekte, globale Variablen,