null

Werbung
```Kapitel 5: Effizienz und Komplexit&auml;t
1
Analyse von insertionSort
insertionSort :: (Ord a) =&gt; [a] -&gt; OrdList a
insertionSort []
= []
insertionSort (a:as) = insert a (insertionSort as)
insert :: (Ord a) =&gt; a -&gt; [a] -&gt; [a]
insert a []
= [a]
insert a (a’:as)
| a &lt;= a’
= a:a’:as
| otherwise = a’:insert a as
(insert.1)
(insert.2)
(insert.2.a)
(insert.2.b)
2
(insert c) (d:z)
⇒ | c &lt;= d
| otherwise
⇒ | True
| otherwise
= c:d:z
(insert.2)
= d:insert c z
= c:d:z
(&lt;=)
= d:insert c z
⇒ c : d : z
(insert.2.a)
beziehungsweise
⇒ | False
| otherwise
⇒ d:insert c z
= c:d:z
(&lt;=)
= d:insert c z
(insert.2.b)
3
T ime(insert c [])
=
1
T ime(insert c (d:z))
=
3,
T ime(insert c (d:z))
=
3 + T ime(insert c z),
falls c 6 d
falls c &gt; d
4
T ime(insert c [])
=
1
T ime(insert c (d:z))
=
3,
T ime(insert c (d:z))
=
3 + T ime(insert c z),
falls c 6 d
falls c &gt; d
T ime(isort [])
=
1
T ime(isort (a:x))
=
1 + T ime(isort x ⇒ v) + T ime(insert a v)
4
t_insertionSort :: (Ord a) =&gt; [a] -&gt; (Int,OrdList a)
t_insertionSort []
= (1,[])
t_insertionSort (a:as) = (t+u+1,ys)
where (t,xs) = t_insertionSort as
(u,ys) = t_insert a xs
t_insert :: (Ord a) =&gt; a -&gt; [a] -&gt; (Int,[a])
t_insert a []
= (1,[a])
t_insert a (a’:as)
| a &lt;= a’
= (3,a:a’:as)
| otherwise = (t+3,a’:xs)
where (t,xs) = t_insert a as
5
Untere und obere Schranken
T isort (n) 6 T ime(isort [a1 ,...,an ]) 6 T isort (n)
6
Untere und obere Schranken
T isort (n) 6 T ime(isort [a1 ,...,an ]) 6 T isort (n)
T isort (n)
=
min{ T ime(isort x) | length x = n }
T isort (n)
=
max{ T ime(isort x) | length x = n }
6
T insert (0)
=
1
T insert (n + 1)
=
3
T insert (0)
=
1
T insert (n + 1)
=
3 + T insert (n)
7
T insert (0)
=
1
T insert (n + 1)
=
3
T insert (0)
=
1
T insert (n + 1)
=
3 + T insert (n)
T isort (0)
=
1
T isort (n + 1)
=
1 + T insert (n) + T isort (n)
T isort (0)
=
1
T isort (n + 1)
=
1 + T insert (n) + T isort (n)
7
&gt; rsolve({insert(n) = 3 + insert(n-1), insert(0)=1, isort(n) = 1 +
insert(n-1) + isort(n-1), isort(0)=1},{insert,isort});
3 2 1
{insert(n ) = 1 + 3 n, isort(n ) = 1 + n + n }
2
2
8
&gt; rsolve({insert(n) = 3 + insert(n-1), insert(0)=1, isort(n) = 1 +
insert(n-1) + isort(n-1), isort(0)=1},{insert,isort});
3 2 1
{insert(n ) = 1 + 3 n, isort(n ) = 1 + n + n }
2
2
T insert (0)
=
1
T insert (n + 1)
=
3
T insert (n)
=
3n + 1
T isort (0)
=
1
T isort (n + 1)
=
4n + 1
T isort (n)
=
(3/2)n2 + (1/2)n + 1
8
Asymptotische Zeit- und Platzeffizienz
Θ(g)
=
{ f | (∃n0 , c1 , c2 )(∀n &gt; n0 ) c1 g(n) 6 f (n) 6 c2 g(n) }
(1)
Ist f ∈ Θ(g), so hei&szlig;t g asymptotische Schranke von f .
9
Asymptotische Zeit- und Platzeffizienz
Θ(g)
=
{ f | (∃n0 , c1 , c2 )(∀n &gt; n0 ) c1 g(n) 6 f (n) 6 c2 g(n) }
(1)
Ist f ∈ Θ(g), so hei&szlig;t g asymptotische Schranke von f .
T insert (n)
∈
Θ(1)
T insert (n)
∈
Θ(n)
T isort (n)
∈
Θ(n)
T isort (n)
∈
Θ(n2 )
9
f ∈ Θ(f )
(Reflexivit&auml;t)
(2)
f ∈ Θ(g) ∧ g ∈ Θ(h) ⇒ f ∈ Θ(h)
(Transitivit&auml;t)
(3)
f ∈ Θ(g) ⇒ g ∈ Θ(f )
(Symmetrie)
(4)
cf ∈ Θ(f )
(5)
na + nb ∈ Θ(na ) f&uuml;r a &gt; b
(6)
loga n ∈ Θ(logb n)
(7)
10
Untere und obere asymptotische Schranken
Ω(g)
=
{ f | (∃n0 , c)(∀n &gt; n0 ) cg(n) 6 f (n) }
(8)
O(g)
=
{ f | (∃n0 , c)(∀n &gt; n0 ) f (n) 6 cg(n) }
(9)
Ist f ∈ Ω(g), so hei&szlig;t g untere asymptotische Schranke von f . F&uuml;r f ∈ O(g) hei&szlig;t g
entsprechend obere asymptotische Schranke von f .
11
Effizienz strukturell rekursiver Funktionen
T insert (0)
=
0
T insert (n + 1)
=
1 + T insert (n)
T isort (0)
=
0
T isort (n + 1)
=
T insert (n) + T isort (n)
12
Effizienz strukturell rekursiver Funktionen
T insert (0)
=
0
T insert (n + 1)
=
1 + T insert (n)
T isort (0)
=
0
T isort (n + 1)
=
T insert (n) + T isort (n)
C(0)
=
c
C(n + 1)
=
f (n + 1) + kC(n)
C(n)
=
n
k c+
n
X
kn−i f (i)
(10)
i=1
12
T insert (n)
=
n
X
1 = n ∈ Θ(n)
i=1
T isort (n)
=
n
X
i=1
i−1=
1
n(n − 1) ∈ Θ(n2 )
2
13
Platzbedarf von isort
isort [a1 , ..., an−1 , an ]
⇒
insert a1 (&middot; &middot; &middot; (insert an−1 (insert an [])) &middot; &middot; &middot;)
⇒
[aπ(1) , ..., aπ(n−1) , aπ(n) ]
14
Platzbedarf von isort
isort [a1 , ..., an−1 , an ]
⇒
insert a1 (&middot; &middot; &middot; (insert an−1 (insert an [])) &middot; &middot; &middot;)
⇒
[aπ(1) , ..., aπ(n−1) , aπ(n) ]
Space(insert a x)
∈
Θ(length x)
Space(isort x)
∈
Θ(length x)
14
Worst-case Laufzeit von sortTree
sortTree :: Tree Integer -&gt; [Integer]
sortTree (Leaf a) = [a]
sortTree (Br l r) = merge (sortTree l) (sortTree r)
merge
merge
merge
merge
|
|
:: (Ord a) =&gt;
[]
bs
(a:as) []
(a:as) (b:bs)
a &lt;= b
otherwise
OrdList a -&gt; OrdList a -&gt; OrdList a
= bs
= a:as
= a:merge as (b:bs)
= b:merge (a:as) bs
15
T merge (m, n)
=
m+n−1
f&uuml;r m, n &gt; 1
16
T merge (m, n)
f&uuml;r m, n &gt; 1
m+n−1
=
n = Zahl der Bl&auml;tter (size):
T sT (1)
=
0
T sT (n)
=
n − 1 + max{ T sT (i) + T sT (n − i) | 0 &lt; i &lt; n }
n
1
2
3
4
5
6
7
8
9
T sT (n) 0
1
3
6
10
15
21
28
36
T sT (n)
=
n
X
i=1
i−1=
1
n(n − 1) ∈ Θ(n2 )
2
Schlechtester Fall: entarteter Baum
16
n = Tiefe (depth):
0
T sT (0)
0
T sT (n + 1)
0
T sT (n)
=
n
X
i=1
n−i
2
i
=
0
=
2n+1 − 1 + 2T sT (n)
(2 − 1) =
n
X
0
2n − 2n−i = n2n − 2n + 1 ∈ Θ(n2n )
i=1
Schlechtester Fall: ausgeglichener Baum
17
T ime(sortTree t)
00
T sT (s, d)
6
=
depth t*size t
sd
18
Ende 5.2 und 5.3 fehlen.
19
Problemkomplexit&auml;t
Bisher:
isort: „worst case“-Laufzeit von Θ(n2 )
mergeSort: „worst case“-Laufzeit von Θ(n log n)
Effizienz eines Sortierverfahrens
20
Problemkomplexit&auml;t
Bisher:
isort: „worst case“-Laufzeit von Θ(n2 )
mergeSort: „worst case“-Laufzeit von Θ(n log n)
Effizienz eines Sortierverfahrens
Jetzt:
Komplexit&auml;t des Sortierproblems
20
Entscheidungsb&auml;ume
a1&lt;=a2
/
\
[a1,a2] [a2,a1]
a1&lt;=a2
/
\
a1&lt;=a3
a2&lt;=a3
/
\
/
\
a2&lt;=a3 [a3,a1,a2]
a1&lt;=a3 [a3,a2,a1]
/
\
/
\
[a1,a2,a3] [a1,a3,a2] [a2,a1,a3] [a2,a3,a1]
21
T imesort (n) &gt; log2 (n!)
22
T imesort (n) &gt; log2 (n!)
Die Fakult&auml;tsfunktion l&auml;&szlig;t sich mit der Stirlingschen Formel absch&auml;tzen:
n n
√
n! &gt; 2πn
.
e
22
Insgesamt erhalten wir
T imesort (n) &gt; log2
= log2
√
√
2πn
n n e
2πn + log2
n n
e
n n
= log2 (2πn)1/2 + log2
e
1
n
= log2 (2πn) + n log2
2
e
1
1
= log2 (2π) + log2 n + n log2 n − n log2 e
2
2
∈ Θ(n log n)
23
Der Weg zu einer guten Probleml&ouml;sung
1. Man verschafft sich Klarheit &uuml;ber die Komplexit&auml;t des zu l&ouml;senden Problems.
2. Man entwickelt einen Algorithmus, dessen Effizienz in der Klasse der
Problemkomplexit&auml;t liegt. Asymptotisch gesehen, ist dieser bereits „optimal“.
3. Man analysiert die konstanten Faktoren des Algorithmus und sucht diese zu
verbessern.
24
Optimierung von mergeSort
build :: [a] -&gt; Tree a
build []
= Nil
build [a]
= Leaf a
build (a:as) = Br (build (take k as))(build (drop k as))
where k = length as ‘div‘ 2
25
Optimierung von mergeSort
build :: [a] -&gt; Tree a
build []
= Nil
build [a]
= Leaf a
build (a:as) = Br (build (take k as))(build (drop k as))
where k = length as ‘div‘ 2
build’’ :: [a] -&gt; Tree a
build’’ as = buildn (length as) as
where buildn :: Int -&gt; [a] -&gt; Tree a
buildn 1 (a:as) = Leaf a
buildn n as
= Br (buildn k (take k as))
(buildn (n-k) (drop k as))
where k = n ‘div‘ 2
25
T build (n) = 5n + 2n log2 n − 4
T build00 (n) = 5n + n log2 n − 4
26
build’ :: [a] -&gt; Tree a
build’ as = fst (buildSplit (length as) as)
buildSplit n as = (Br l r, as’’)
where k = n ‘div‘ 2
(l,as’) = buildSplit
k as
(r,as’’) = buildSplit (n-k) as’
27
build’ :: [a] -&gt; Tree a
build’ as = fst (buildSplit (length as) as)
buildSplit n as = (Br l r, as’’)
where k = n ‘div‘ 2
(l,as’) = buildSplit
k as
(r,as’’) = buildSplit (n-k) as’
T buildSplit (n)
=
6 + T buildSplit (bn/2c) + T buildSplit (dn/2e)
T buildSplit (1)
=
1
27
build’ :: [a] -&gt; Tree a
build’ as = fst (buildSplit (length as) as)
buildSplit n as = (Br l r, as’’)
where k = n ‘div‘ 2
(l,as’) = buildSplit
k as
(r,as’’) = buildSplit (n-k) as’
T buildSplit (n)
=
6 + T buildSplit (bn/2c) + T buildSplit (dn/2e)
T buildSplit (1)
=
1
F&uuml;r n = 2k : T buildSplit (2k ) = 6(2k+1 − 1) = 12n − 6 ∈ Θ(n)
27
mergeSort as = sortTree (build as)
build []
= Nil
build [a]
= Leaf a
build (a:as) = Br (build (take k as))(build (drop k as))
where k = length as ‘div‘ 2
28
mergeSort []
= sortTree(build [])
= sortTree Nil
mergeSort [a]
= sortTree(build [a])
= sortTree (Leaf
mergeSort (a:as) = sortTree(build (a:as))
= sortTree(Br (build (take k as)) (build
where k = length
= merge (sortTree (build (take k as))
sortTree (build (drop k as)))
where k = length
= merge (mergeSort (take k as)
mergeSort (drop k as)))
where k = length
a)
= []
= [a]
(drop k as)))
as ‘div‘ 2
as ‘div‘ 2
as ‘div‘ 2
29
mergeSort’ []
= []
mergeSort’ [a]
= [a]
mergeSort’ (a:as) = merge (mergeSort (take k as))
(mergeSort (drop k as))
where k = length as ‘div‘ 2
30
mtest = mergeSort [1..10000]
mtest’ = mergeSort’ [1..10000]
31
Top down Baumkonstruktion
[8, 3, 5, 3, 6, 1]
[8, 3, 5]
[3, 6, 1]
[3, 5]
8
3
5
[6, 1]
3
[3, 5]
[3, 5, 8]
6
1
[1, 6]
[1, 3, 6]
[1, 3, 3, 5, 6, 8]
32
Bottom up Baumkonstruktion
/\
/t1\
----
/\
/t2\
----
/\
/t3\
----
/\
/t4\
----
/\
/t5\
----
/\
/t6\
----
/\
/t7\
----
33
Bottom up Baumkonstruktion
/\
/t1\
----
/\
/t2\
----
/\
/t3\
----
o
/
/\
/t1\
----
/\
/t4\
----
/\
/t5\
----
o
\
/\
/t2\
----
/
/\
/t3\
----
/\
/t6\
----
/\
/t7\
----
o
\
/\
/t4\
----
/
/\
/t5\
----
\
/\
/t6\
----
/\
/t7\
----
33
bubuild :: [a] -&gt; Tree a
bubuild = buildTree . map Leaf
buildTree
buildTree
buildTree
buildTree
:: [Tree a] -&gt; Tree a
[] = Nil
[t] = t
ts = buildTree (buildLayer ts)
buildLayer
buildLayer
buildLayer
buildLayer
:: [Tree a] -&gt; [Tree a]
[]
= []
[t]
= [t]
(t1:t2:ts) = Br t1 t2:buildLayer ts
34
Ber&uuml;cksichtigung von L&auml;ufen
16 14 13 4 9 10 11 5 1 15 6 2 3 7 8 12
16 14 13 4 | 9 10 11 | 5 1 | 15 6 2 | 3 7 8 12.
35
runs
runs
runs
runs
:: [a] -&gt;
[]
=
[a]
=
(a:b:x) =
[[a]]
[[]]
[[a]]
if a&lt;=b then ascRun b [a] x
else descRun b [a] x
ascRun, descRun :: a -&gt; [a] -&gt; [a] -&gt; [[a]]
ascRun a as []
= [reverse (a:as)]
ascRun a as (b:y) = if a&lt;=b then ascRun b (a:as) y
else reverse (a:as):runs (b:y)
descRun a as []
= [a:as]
descRun a as (b:y) = if a&lt;=b then (a:as):runs (b:y)
else descRun b (a:as) y
36
Geschmeidiges Merge-Sort
smsort :: Ord a =&gt; [a] -&gt; [a]
smsort = mergeRuns . build’ . runs
mergeRuns :: Ord a =&gt; Tree [a] -&gt; [a]
mergeRuns (Leaf x) = x
mergeRuns (Br l r) = merge (mergeRuns l) (mergeRuns r)
37
Nachtrag zu Listen
[1 ..] Liste der positiven Zahlen,
[1 .. 99] Liste der positiven Zahlen bis einschlie&szlig;lich 99,
[1, 3 ..] Liste der ungeraden, positiven Zahlen,
[1, 3 .. 99] Liste der ungeraden, positiven Zahlen bis einschlie&szlig;lich 99.
38
Listenbeschreibungen (list comprehensions)
squares :: [Integer]
squares = [n*n | n &lt;- [0..99]]
39
Listenbeschreibungen (list comprehensions)
squares :: [Integer]
squares = [n*n | n &lt;- [0..99]]
map’ f x = [f a | a &lt;- x]
squares = map (\n -&gt; n * n) [0..99]
a ‘elem‘ x = or [a==b | b &lt;- x]
39
divisors :: (Integral a) =&gt; a -&gt; [a]
divisors n = [d | d &lt;- [1..n], n ‘mod‘ d == 0]
primes :: (Integral a) =&gt; [a]
primes = [n | n &lt;- [2..], divisors n == [1,n]]
40
divisors :: (Integral a) =&gt; a -&gt; [a]
divisors n = [d | d &lt;- [1..n], n ‘mod‘ d == 0]
primes :: (Integral a) =&gt; [a]
primes = [n | n &lt;- [2..], divisors n == [1,n]]
qsort’’ :: (Ord a) =&gt; [a] -&gt; [a]
qsort’’ []
= []
qsort’’ (a:x) = qsort’’ [b | b &lt;- x, b &lt; a]
++ [a]
++ qsort’’ [ b | b &lt;- x, b &gt;= a]
40
[(a,b) | a &lt;- [0,1], b &lt;- [1..3]]
⇒
[(0,1),(0,2),(0,3),(1,1),(1,2),(1,3)]
41
Felder (Arrays)
squares’ :: Array Int Int
squares’ = array (0,99) [(i,i*i) | i &lt;- [0..99]]
squares’!7 ⇒ 7*7 ⇒ 49
42
Felder (Arrays)
squares’ :: Array Int Int
squares’ = array (0,99) [(i,i*i) | i &lt;- [0..99]]
squares’!7 ⇒ 7*7 ⇒ 49
multTable :: Array (Int, Int) Int
multTable = array ((0,0),(9,9))
[((i,j),i*j) | i &lt;- [0..9], j &lt;- [0..9]]
42
Funktionen auf Indextypen
range
inRange
array
bounds
assocs
(!)
::
::
::
::
::
::
(Ix
(Ix
(Ix
(Ix
(Ix
(Ix
a)
a)
a)
a)
a)
a)
=&gt;
=&gt;
=&gt;
=&gt;
=&gt;
=&gt;
(a,a)
(a,a)
(a,a)
Array
Array
Array
-&gt; [a]
-&gt; a -&gt; Bool
-&gt; [(a,b)] -&gt; Array a b
a b -&gt; (a,a)
a b -&gt; [(a,b)]
a b -&gt; a -&gt; b
43
Funktionstabellierung
tabulate :: (Ix a) =&gt; (a -&gt; b) -&gt; (a,a) -&gt; Array a b
tabulate f bs = array bs [(i, f i) | i &lt;- range bs]
44
Funktionstabellierung
tabulate :: (Ix a) =&gt; (a -&gt; b) -&gt; (a,a) -&gt; Array a b
tabulate f bs = array bs [(i, f i) | i &lt;- range bs]
∀i &lt;- range bs : (tabulate f bs)!i == f i
44
Anwendung Tabellierung
fib n = t!n
where t = tabulate f (0,n)
f 0 = 1
f 1 = 1
f n = t!(n-2) + t!(n-1)
45
listArray :: (Ix a) =&gt; (a,a) -&gt; [b] -&gt; Array a b
listArray bs vs = array bs (zip (range bs) vs)
zip [a1 ,a2 ,...] [b1 ,b2 ,...] = [(a1 ,b1 ),(a2 ,b2 ),...]
46
Bin&auml;re Suche
binarySearch :: (Ord b, Integral a, Ix a) =&gt; Array a b -&gt; b -&gt; Bool
binarySearch a e = within (bounds a)
where within (l,r) = l &lt;= r
&amp;&amp; let m = (l + r) ‘div‘ 2
in case compare e (a!m) of
LT -&gt; within (l, m-1)
EQ -&gt; True
GT -&gt; within (m+1, r)
47
Anwendung: Ein lineares Sortierverfahren
countingSort :: (Ix a) =&gt; (a, a) -&gt; [a] -&gt; [a]
countingSort bs x = [ a | (a,n) &lt;- assocs t, i &lt;- [1..n]]
where t = accumArray (+) 0 bs [(a,1) | a &lt;- x, inRange bs a]
48
Anwendung: Ein lineares Sortierverfahren
countingSort :: (Ix a) =&gt; (a, a) -&gt; [a] -&gt; [a]
countingSort bs x = [ a | (a,n) &lt;- assocs t, i &lt;- [1..n]]
where t = accumArray (+) 0 bs [(a,1) | a &lt;- x, inRange bs a]
listSort :: (Ix a) =&gt; (a, a) -&gt; [[a]] -&gt; [[a]]
listSort bs xs
| drop 8 xs == [] = insertionSort xs
| otherwise
= [[] | [] &lt;- xs] ++
[a:x | (a, ys) &lt;- assocs t, x &lt;- listSort bs ys]
where t = accumArray (\y b -&gt; b:y) [] bs [(a,x) | (a:x) &lt;- xs]
48
Array-Update
(//) :: (Ix a) =&gt; Array a b -&gt; [(a, b)] -&gt; Array a b
unitMatrix :: (Ix a, Num b) =&gt; (a,a) -&gt; Array (a,a) b
unitMatrix [email protected](l,r) = array bs’ [(ij,0) | ij &lt;- range bs’]
// [((i,i),1) | i &lt;- range bs]
where bs’ = ((l,l),(r,r))
49
Pascalsches Dreieck
0
1
2
3
4
5
6 7
8
0 1
1 1
1
2 1
2
1
3 1
3
3
1
4 1
4
6
4
1
5 1
5
10
10
5
1
6 1
6
15
20
15
6
7 1
7
21
35
35
21
7 1
8 1
8
28
56
70
56
28 8
1
1
50
pascalsTriangle :: Int -&gt; Array (Int,Int) Int
pascalsTriangle n = a
where a = array ((0,0),(n,n)) (
[((i,j),0) | i &lt;- [0..n], j &lt;- [i+1..n]]
++ [((i,0),1) | i &lt;- [0..n]]
++ [((i,i),1) | i &lt;- [1..n]]
++ [((i,j),a!(i-1,j) + a!(i-1,j-1)) | i &lt;- [2..n],
j &lt;- [1..i-1]])
51
Binomialkoeffizienten
(x + y)n
=
!
n
X
n k n−k
x y
k
k=0
n
k
!
=
8
&lt;
n!
(n−k)!k!
06k6n
:
0
06n&lt;k
,
52
```