Algorithmen und Programmieren I Übung 8 (25 P) Ausgabe: Mo. 3 1.00 Abgabe: Mo., 10 1.00, 12.05 in der Vorlesung H. Schweppe, FUB, WS 99/00 Aufgabe 1 (8 P) Winkel können auf drei verschiedene Arten repräsentiert werden: als Winkel im Gradmaß in Neugrad (Gon) oder im Bogenmaß. Das Gradmaß besteht aus einer Angabe von Grad, Minuten und Sekunden. Der Vollwinkel hat bekanntlich 360°, 1° = 60' (Minuten), 1' hat 60'' (Sekunden). In der Vermessungstechnik wird der Vollwinkel in 400 Neugrad eingeteilt, 1 Neugrad = 100 Neuminuten, 1 Neuminute = 100 Neusekunden. Beim Bogenmaß (Einheit rad) gilt: 2π rad entsprechen dem Vollwinkel. π ist in Haskell als Konstante pi definiert. a) (1 P) Definieren Sie einen algebraischen Datentyp Winkel , der die Repräsentation in allen drei Einheiten gestattet. Grade und Minuten sollten ganzzahlig, Sekunden , Neugrad und rad als Gleitpunktzahlen gehalten werden. b) (3 P) Geben Sie Deklarationen an, so daß alpha , beta :: Winkel der Größe nach verglichen werden können: alpha == beta und alpha < beta (Hinweis: Interne Berechnungsbasis sollte rad sein. Ferner werden Winkel in normalisierter Darstellung gehalten: 30° = -330° = 390° . Implementieren Sie eine Normalisierungsfunktion und eine Wandlungsfunktion). c) (1 P) Die Funktionen add und sub berechnen die Summe bzw. die Differenz zweier Winkel. Das Ergebnis soll wieder in normalisierter Darstellung sein. Geben Sie add, sub an. d) (3 P) Die Anzeige eines Winkels soll in gewohnter Altgrad-Darstellung erfolgen. Gesucht ist eine Implementierung der show-Funktion (Format z.B.: 32 Grad 20’ 12.3’’). Aufgabe 2 (12 P) In allen Teilaufgaben geht es, soweit nichts Anderes gesagt, um binäre Bäume vom in der VL definierten Typ data Tree a = Empty | N (Tree a) (Tree a) a . a) (1 P) Definieren Sie eine Funktion inorder, die die Liste der Knotenwerte eines binären Baums in inorder-Reihenfolge ("linker Teilbaum, Wurzel, rechter Teilbaum") berechnet. b) (2 P) Die Länge des Pfades von der Wurzel w eines Baums zum Knoten k heißt Tiefe von k. (w hat die Tiefe 0, die direkten Nachfolger von w die Tiefe 1 usw.). Unter der Höhe versteht man die maximale Tiefe aller Knoten eines binären Baums. Schreiben Sie eine Funktion height :: Tree a -> Int, die die Höhe des Argument berechnet. c) (2 P) Schreiben Sie eine Funktion reflect :: Tree a -> Tree a , die in einem binären Baum jeweils linken und rechten Teilbaum vertauscht. d) (1 P) Gesucht ist eine Funktion zur Berechnung der Summe der Knotenwerte eines binären Baums Tree Int. e) (1 P) Zu definieren ist eine Funktion mapNodes, die - analog zu map für Listen - eine Funktion f auf alle Knoten eines binären Baums anwendet. f) (1 P) Gesucht ist die Funktion mapLeafs, die eine Funktion f auf die Blätter des binären Baums anwendet. Warum benötigt man hier einen restriktiveren Typ als in Teilaufgabe f) ? Zur Erinnerung: Knoten heißen Blätter, wenn linker und rechter Teilbaum leer (Empty) sind. g) (2 P) Gesucht ist eine Funktion, die entscheidet, ob ein bestimmter Int-Wert n Knoten eines Baums vom Typ Tree Int ist. h) (2 P) Gesucht sind Funktionen, die Minimum bzw. Maximum eines Baums vom Typ Tree Int liefern. Stützen Sie die Definition so auf eine Funktion minMax:: Tree Int -> (Int,Int) ab, dass der Baum nur einmal durchlaufen ("traversiert") wird. Aufgabe 3 (5 P) Definieren Sie in a) EBNF und b) mit Hilfe von Syntaxdiagrammen eine Sprache, mit der man für ein Programm die Relation "stützt sich direkt ab auf" ausdrücken kann. Symbolisch wird das für g und h mit g -> h beschrieben. Als Bezeichner werden nur die Kleinbuchstaben verwendet. Stützt sich eine Funktion g auf mehrere andere g1,g2,...gn ab, wird das durch den Ausdruck g -> g1,...,gn beschrieben. Zwei Ausdrücke dieser Art werden durch ein Semikolon getrennt. Leerzeichen dürfen überall außer in -> auftreten. Beispiel: Wenn c sich auf b und d, b sich auf e , d sich auf e und f abstützt, lautet der Ausdruck der "Stütz-Sprache": c -> b, d; b -> e; d -> e, f Aufgabe 4 (freiwillig, 8 Zusatzpunkte) Das Suchen nach einem Wert in den Knoten eines Baums – wie in Aufgabe 2 g) ist aufwendig. Ein hinsichtlich Laufzeit viel besseres Ergebnis erzielt man, wenn für alle Knoten k eines Baums die Invariante gilt: der Wert v(k) von k ist größer oder gleich allen Knotenwerten v(k’) im linken Teilbaum und kleiner als die Werte aller Knoten v(k’’) im rechten Teilbaum, also: ∀ k∀ k’ aus linkem Teilbaum von k : v(k’) ≤ v(k) ∧ ∀ ∀ k k’aus rechtem Teilbaum von k : v(k’’) > v(k) a) Reimplementieren Sie die Funktion aus Aufgabe 2 g) für einen Baum, der die Invariante erfüllt. b) Definieren Sie eine Funktion insert:: Tree a -> a -> Tree a , die einen Knotenwert unter Beachtung der Invariante in den Baum einträgt. c) Definieren Sie mit Hilfe einer Faltungsfunktion ein Funktion invertList :: Tree a -> [a] -> Tree a , die die Listenelemente nacheinander in einen anfangs leeren Baum einfügt. Begründen Sie, warum die Reihenfolge der Listenelemente einen Einfluss auf den entstehenden Baum hat (Extremfälle?)