Informatik A

Werbung
Informatik A
Übung 6
Musterlösung
(Robert Gottwald, Thimo Wellner)
1.
Haskell und Rekursion I (4 Punkte)
Implementieren Sie die Rekursion zur Berechnung der Binominialkoeffizienten. Geben Sie
die ersten 12 Zeilen des Pascalschen Dreieckes auf dem Bildschirm aus. Die einzelnen
Zeilen sollten linksbündig sein, danach jeweils eine Leerzeile, zwischen den Einträgen
einer Zeile jeweils ein Leerzeichen.
Lösung:
--Aufgabe 1
binomial :: Int -> Int -> Integer
binomial _ 0 = 1
binomial n k
| n>k = (binomial (n-1) (k-1)) + (binomial (n-1) k)
| n==k = 1
| otherwise = 0
Hierbei war wichtig, die Funktion wirklich rekursiv zu schreiben, da sonst auch schnell mit der
Fakultätsfunktion die Darstellungsgrenze des Int-Bereichs erreicht gewesen wäre.
drawPascal :: Int -> IO()
drawPascal n = putStr (drawHelper 0 n)
where
pascalLine n = concat (map (++" ") (map show (map (binomial n) [0..n])))
drawHelper i n
| i==n = ""
| otherwise = (pascalLine i) ++ "\n" ++ (drawHelper (i+1) n)
(Eine weitere Implementierung ist im pad-spline unter http://pad.spline.de/MTDAb6W1iF zu finden,
geschrieben von Thimo Wellner.)
2.
Palindrome und Rekursion II (4+2 Punkte)
(a)
Definieren Sie rekursiv(!) eine Funktion isPalind, die feststellt, ob ein String ein
Palindrom ist.
Zur Erinnerung, ein Palindrom ist ein String, der von vorn bzw. hinten gelesen
dasselbe ergibt. Um es ein bisschen anspruchsvoller zu machen soll bei Buchstaben
nicht zwischen Groß- und Kleinschreibung unterschieden werden. Also „Rentner"
ist ein Palindrom.
Lösung:
--Aufgabe 2
import Char –- notwendig, da chr und ord nur in dieser Bibliothek stehen.
--Hilfsfunktion
lcase :: Char -> Char
lcase c = if elem c (['A'..'Z']++['Ä','Ö','Ü']) then (chr (32+ord c)) else c
–- wandelt große Buchstaben in kleine um.
isPalind
isPalind
isPalind
isPalind
:: String -> Bool
[] = True
[x] = True
(x:xs) = (lcase x) == (lcase (last xs)) && (isPalind (init xs))
(b)
Wie viele Palindrome der Länge n ≥ 0 über einem Alphabet Σ der Größe s ≥ 1
gibt es eigentlich? Stellen Sie eine Formel auf und beweisen Sie diese!
Lösung:
Für gerade n gibt es s(n /2) Palindrome, für ungerade n s(((n −1)/ 2)+1) .
Das sind für beide Fälle gerade s⌈ n /2 ⌉ .
Beweis:
Induktion über n:
Anker: Für n = 0 gibt es ein einziges Palindrom, das leere Wort. s⌈ 0 /2 ⌉=s 0=1
Für n = 1 gibt es s Palindrome, die einzelnen Symbole in Σ. s⌈ 1/ 2 ⌉=s1 =s
IV:
IB:
IS:
3.
Für ein beliebiges, aber festes n gilt: Die Anzahl aller Palindrome über n mit s ist s⌈ n /2 ⌉ .
Für n' = n+2 gilt: Die Anzahl aller Palindrome ist s⌈ n ' /2 ⌉=s⌈ (n+2)/2 ⌉=s ⌈(n)/2+1 ⌉
Betrachtet man sich die Palindrome mit Wortlänge n, so ist ersichtlich, dass man daraus
Palindrome der Wortlänge n' = n+2 machen kann, in dem man vorne einen beliebigen
Buchstaben aus Σ anfügt. Der Buchstabe am Ende des Wortes jedoch muss derselbe sein, um die
palindromische Eigenschaft zu bewahren. Somit gibt es
⌈ n /2 ⌉
⌈ n/ 2 ⌉+1
⌈(n)/ 2+1⌉
⌈(n+2)/ 2 ⌉
⌈ n '/ 2 ⌉
s ∗s=s
=s
=s
=s
Palindrome der Länge n' = (n+2).
Buchstabenfrequenz (6 Punkte)
Schreiben Sie eine Funktion frequency :: String -> [(Char,Int)], die feststellt,
welche Buchstaben wie oft in einem String vorkommen. Dabei sollen Klein- und Großbuchstaben nicht
unterschieden werden. Die Häufigkeiten beziehen sich auf die Gesamtzahl der Buchstaben im String,
die anderen Zeichen sollen ignoriert werden. Definieren Sie sich ggf. Hilfsfunktionen.
Lösung:
--Aufgabe 3
frequency :: String -> [(Char,Int)]
frequency a = frequencyHelper a []
where
frequencyHelper [] cs = cs --Hilfsfunktion, die sich den aktuellen Zählstand
--in einer Liste merkt
frequencyHelper (x:xs) cs = frequencyHelper xs (countChar (lcase x) cs)
where
countChar x [] = [(x,1)] --zählt das Zeichen x in dem übergebenen
--Zählstand um 1 hoch
countChar x ((c,n):cs) = if x==c then ((c,n+1):cs) else ((c,n):(countChar x cs))
4.
Simultanes Min-Max (4 Punkte)
Schreiben Sie eine rekursive Funktion zur simultanen Bestimmung des Minimums und
des Maximums in einer Liste von ganzen Zahlen.
Analysieren Sie, wie viele Vergleiche zwischen Listenelementen Ihr Verfahren macht
bei einer Liste der Länge n. Sie sollten mit weniger als 2n -2 Vergleichen auskommen.
Dies erreicht man schon, wenn man getrennt Minimum und Maximum mit jeweils n - 1
Vergleichen bestimmt.
Lösung:
Die Idee für die schnellste Implementierung ist, sich jeweils zwei Werte der Liste gleichzeitig anzuschauen und
sie zuerst zu vergleichen. Das kleinere von beiden kann nicht Maximum sein, das größere nicht Minimum,
wodurch man statt 4 Vergleichen (min, max) für beide Werte nur 3 Vergleiche macht.
--Aufgabe 4
minMax :: [Int] -> (Int,Int)
minMax [] = error "empty list"
minMax [x] = (x,x)
minMax (x:y:xs)
| x<y = minMaxHelper xs [] (x,y)
| otherwise = minMaxHelper xs [] (y,x)
where
minMaxHelper :: [Int] -> [(Int,Int)] -> (Int,Int) -> (Int,Int)
minMaxHelper [] [] (a,b) = (a,b)
minMaxHelper [] ((a,b):ms) (l,g) = minMaxHelper [] ms ((min a l),(max b g))
--wenn die Eingabeliste verarbeitet wurde dann wird das kleinste der Minima und das
größte der Maxima bestimmt
minMaxHelper [x] ms lg = minMaxHelper [] ((x,x):ms) lg
--bestimmt erst den größeren von zwei Paaren und fügt ihn an Liste ms an
minMaxHelper (x:y:xs) ms lg
| x<y = minMaxHelper xs ((x,y):ms) lg
| otherwise = minMaxHelper xs ((y,x):ms) lg
Herunterladen