17
Programmierung 1 - Repetitorium WS 2002/2003 Programmierung 1 - Repetitorium Andreas Augustin und Marc Wagner Homepage: http://info1.marcwagner.info

WS 2002/2003 Programmierung 1 - Repetitorium Andreas Augustin und Marc Wagner

Embed Size (px)

DESCRIPTION

WS 2002/2003 Programmierung 1 - Repetitorium Andreas Augustin und Marc Wagner Homepage: http://info1.marcwagner.info. Dienstag, den 08.04.03 Kapitel 5 Listen. 5.1 Listen als mathematische Objekte. Listen stellen eine endliche Folge von Objekten dar. Listendarstellung :. - PowerPoint PPT Presentation

Citation preview

Programmierung 1 - Repetitorium

WS 2002/2003

Programmierung 1 - Repetitorium

Andreas Augustin und Marc Wagner

Homepage: http://info1.marcwagner.info

Programmierung 1 - Repetitorium

Dienstag, den 08.04.03

Kapitel 5

Listen

Programmierung 1 - Repetitorium

5.1 Listen als mathematische Objekte

Listen stellen eine endliche Folge von Objekten dar.

Listendarstellung :

1. Die leere Folge wird als leeres Tupel dargestellt.2. Eine nichtleere Folge x1,...,xn wird als Paar, das aus x1 und der

Listendarstellung der Folge x2,...,xn besteht, dargestellt.

Beispiele :

[ ] [3] [2,3] [1,2,3]

< > <3,< >> <2,<3,< >>> <1,<2,<3,< >>>>

< > < >

3 < >

< >

2 < >

3 < >

< >

1 < >

2 < >

3 < >

Programmierung 1 - Repetitorium

5.1 Listen als mathematische Objekte

Bei einer nichtleeren Liste <x,xs> bezeichnet man x als den Kopfund xs als den Rumpf der Liste.

Sei X eine Menge. Eine Liste heißt Liste über X, wenn alle ihre ElementeElemente der Menge X sind. Die Listen über X lassen sich mit zwei Regelnkonstruieren :

1. Das leere Tupel ist eine Liste über X.2. Wenn x X und xs eine Liste über X ist, dann ist <x,xs> eine Liste über X.

[x1,...,xm] @ [y1,...,yn] = [x1,..,xm,y1,...,yn]

Die Länge einer Liste xs bezeichnen wir mit |xs|.

|[x1,...,xn]| = n |xs@ys| = |xs| + |ys|

Die leere Liste [ ] bezeichnet man als nil. Für eine nichtleere Liste <x,xs>schreiben wir auch x::xs (lies: x cons xs).

cons klammert nach rechts ⇒ x::(y::xs) = x::y::xs

Programmierung 1 - Repetitorium

5.2 Listen in Standard ML

SML stellt für jeden Typ t einen Listentyp t list zur Verfügung.Die Werte dieses Typs sind alle Listen, die über Werten des Typs t gebildet werden.

[ 1 , 2 , 3 ] Typ: int list Konstruktion: 1 :: ( 2 :: ( 3 :: nil ) )

[ 1.0 , 2.0 , 3.0 ] Typ: real list Konstruktion: 1.0 :: ( 2.0 :: ( 3.0 :: nil ) )

[ [ 2 , 3 ] , [ ] ] Typ: int list list Konstruktion: ( 2 :: ( 3 :: nil ) ) :: ( ( nil ) :: nil )

Der cons-Konstruktor klammert nach rechts : e1 :: e2 :: e3 = e1 :: ( e2 :: e3 )

Beispiele :

1 :: 2 :: 3 :: nil = 1 :: [ 2 , 3 ] = [ 1 , 2 , 3 ]

op::( 2 , nil ) = 2 :: nil = [ 2 ]

true :: false :: true :: nil = [ true , false , true ]

op::( false , op::( true , nil ) ) = false :: [ true ] = [ false , true ]

Programmierung 1 - Repetitorium

5.3 Length, Append, Reverse, Concat und Tabulate

Länge einer Liste (SML: length) : length : ‘a list → int

fun length nil = 0 | length (x::xr) = 1 + length xr

Regeln durch Schlüsselwort „|“ getrennt.Das Muster (Pattern) (x::xr) führt zwei Variablen x und xr ein,die im Rumpf der Regel benutzt werden können.

Prozeduren mit mehreren Regeln bezeichnet man als regelbasiert.

Im Rumpf nicht benutzte Variablen können im Muster der Regel durch dasWildcard-Symbol _ ersetzt werden.

Beispiel : length [1,2,3] = 3

Konkatenation zweier Listen (SML: op@) : append : ‘a list * ‘a list → ‘a listfun append (nil,ys) = ys | append (x::xr,ys) = x :: append(xr,ys)Beispiel : append ( [3] , [1,4] ) = [3,1,4]

Programmierung 1 - Repetitorium

5.3 Length, Append, Reverse, Concat und Tabulate

Reversierung einer Liste (SML: rev) : reverse : ‘a list → ‘a list

fun reverse nil = nil | reverse (x::xr) = reverse xr @ [x]

Beispiel : reverse [1,2,3] = [3,2,1]

Tabulate (SML: List.tabulate) : tabulate : int * ( int → ‘a ) → ‘a listfun tabulate (n,f) = if n<1 then nil else tabulate(n-1,f) @ [f(n-1)]Beispiel : tabulate(5,(fn x => x*x)) = [0,1,4,9,16]

Konkatenation von Elementlisten (SML: List.concat) : concat : ‘a list list → ‘a list

fun concat nil = nil | concat (x::xr) = x @ concat xr

Beispiel : concat [ [3] , [1,2] , [ ] ] = [3,1,2]

tabulate (n,f) = [f(0),...,f(n-1)]

Programmierung 1 - Repetitorium

5.4 Map, Filter, Exists und All

Map (SML: map) : map : (‘a → ‘b) → ‘a list → ‘b list

fun map f nil = nil | map f (x::xr) = (f x)::(map f xr)

Beispiel : map op~ [2,4,3] = [~2,~4,~3]

Filter (SML: List.filter) : filter : (‘a → bool) → ‘a list → ‘a listfun filter f nil = nil | filter f (x::xr) = if f x then x :: filter f xr else filter f xrBeispiel : filter (fn x => x>2) [0,1,2,4,7] = [4,7]

Filter liefert alle Elemente einer Liste, für die die Prozedur f den Wert true liefert.

Ambige Deklaration : val maplen = map length(Warning! Value polymorphism ...)

Problem behebbar durch einen nicht expansiven Ausdruck.Man verwende eine Abstraktion : val maplen = fn xs => map length xs

Programmierung 1 - Repetitorium

5.4 Map, Filter, Exists und All

Exists (SML: List.exists) : exists : (‘a → bool) → ‘a list → bool

fun exists f nil = false | exists f (x::xr) = f x orelse exists f xr

Beispiel : exists (fn x => x>2) [0,1,2,4,7] = true

All (SML: List.all) : all : (‘a → bool) → ‘a list → boolfun all f nil = true | all f (x::xr) = f x andalso all f xr

Beispiel : all (fn x => x>2) [0,1,2,4,7] = false

All testet, ob jedes Element der Liste true liefert für die Prozedur f.

e1 orelse e2 = if e1 then true else e2e1 andalso e2 = if e1 then e2 else false

Exists testet, ob mind. ein Element der Liste true liefert für die Prozedur f.

Programmierung 1 - Repetitorium

5.5 Faltungsprozeduren

fun foldl f s nil = s | foldl f s (x::xr) = foldl f (f(x,s)) xrfun foldr f s nil = s | foldr f s (x::xr) = f(x,foldr f s xr)

Typ : (‘a * ‘b → ‘b) → ‘b → ‘a list → ‘b

Funktionsweise : foldr f s [x1,...,xn] = f(x1,...f(xn-1,f(xn,s))...)foldl f s [x1,...,xn] = f(xn,...f(x2,f(x1,s))...)

f

x1 f

x2 f

x3 s

f

x3 f

x2 f

x1 s

foldr f s [x1,x2,x3] foldl f s [x1,x2,x3]

Programmierung 1 - Repetitorium

5.5 Faltungsprozeduren

fun foldr f s xs = foldl f s rev(xs)

fun length xs = foldl (fn (x,n) => n+1) 0 xs

fun append (xs,ys) = foldr op:: ys xs

fun rev xs = foldl op:: nil xs

fun map f = foldr (fn (x,yr) => (f x)::yr) nil

fun concat xs = foldr op@ nil xs

fun exists f = foldl (fn (x,b) => b orelse f x) false

fun all f = foldl (fn (x,b) => b andalso f x) true

Vereinfachte Deklarationen einiger Listenprozeduren :

Programmierung 1 - Repetitorium

5.6 hd, tl, null und Ausnahmen

fun hd nil = raise Empty | hd (x::xr) = xfun tl nil = raise Empty | tl (x::xr) = xr

hd : ‘a list → ‘a

tl : ‘a list → ‘a list

fun null nil = true | null (x::xr) = false

null : ‘a list → bool

hd liefert den Kopf (head), tl liefert den Rumpf (tail) einer Liste.

Auf eine leere Liste angewendet, werfen sie die Ausnahme Empty. (exception)

Wenn bei der Ausführung eines Programms eine Ausnahme geworfen wird,bricht der Interpreter die Ausführung des Programms ab und liefert eineentsprechende Fehlermeldung.

null testet, ob eine Liste leer ist.

Oft kann man die Beschränkung auf einen Typ mit Gleichheit umgehen,indem man in der Prozedur null xs an Stelle von xs=nil verwendet.Typen mit Gleichheit werden z.B. mit ‘‘a (lies alpha 2-strich) bezeichnet,im Gegensatz zum allgemeinen Typ ‘a (lies alpha).

Programmierung 1 - Repetitorium

5.7 Regelbasierte Prozeduren

Regel: <Prozedurbezeichner><Muster>...<Muster> = <Rumpf>

Muster: Konstanten, Bezeichner, _ , (M1 : t), (M1::M2), (M1,...,Mn) und [M1,...,Mn]mit M1,...,Mn Muster und t Typ

Ein Bezeichner darf höchstens einmal in einem Muster (pattern) auftretenund wird als Variable der Regel bezeichnet.

Ein Wert v trifft ein Muster M (pattern matching), wenn ...

1. M ist ein Bezeichner oder das Wildcard-Symbol2. M ist eine Konstante und v ist der Wert, den die Konstante beschreibt

3. M hat die Form (M‘ : t) und v trifft M‘ (der Typ spielt also keine Rolle!)4. M hat die Form (M1 :: M2) und v ist eine Liste, deren Kopf M1 und

deren Rumpf M2 trifft.5. M hat die Form [M1,...,Mn] und v ist eine n-elementig Liste [v1,...,vn],

deren Elemente vi die entsprechenden Muster Mi treffen.6. M hat die Form (M1,...,Mn) und v ist ein n-stelliges Tupel <v1,...,vn>,

dessen Komponenten vi die entsprechenden Muster Mi treffen.

Programmierung 1 - Repetitorium

5.7 Regelbasierte Prozeduren

Die Regeln einer Prozedur heißen disjunkt, wenn ihre Muster disjunkt sind,also wenn kein Wert mehr als eines der Muster trifft.

Die Regeln einer Prozedur heißen erschöpfend, wenn ihre Muster denArgumenttyp der Prozedur erschöpfen, also wenn jeder Wert des Argumenttypsmindestens eines der Muster trifft.

Falls die Regeln disjunkt sind spielt die Reihenfolge keine Rolle,andernfalls ist die Reihenfolge sehr wichtig, da eine Regel nur dannanwendbar ist, wenn die vor ihr stehenden Regeln nicht anwendbar sind.

Unerwünschte Argumente sollte man mithilfe einer zusätzlichenAusnahmeregel behandeln.

Programmierung 1 - Repetitorium

5.8 Sortieren von ganzzahligen Listen

Eine Liste [x1,...,xn] ( ) heißt ℒ ℤ sortiert, wenn x1 ≤ ... ≤ xn gilt.fun sorted (x::y::zs) = x<=y andalso sorted(y::zs) | sorted _ = trueZwei Listen heißen bis auf Permutation gleich, wenn sie bis auf die Reihenfolgeihrer Elemente gleich sind.

Es existiert genau eine Sortierfunktion sort ℒ (ℤ) → ℒ (ℤ).

∀ xs,ys ℒ (ℤ) : xs und ys bis auf Permutation gleich ⇔ sort(xs) = sort(ys)

Sortieren durch Einfügen : Schema: sort(x::xr) = insert(x,sort(xr))fun insert (x,nil) = [x] | insert (x,y::yr) = if x<=y then x::y::yr else y::insert(x,yr)val isort = foldl insert nil

insert fügt das Element x in eine sortierte Liste xs ein, so dass die soentstehende List immer noch sortiert ist.isort realisiert Sortieren durch Einfügen.

Programmierung 1 - Repetitorium

5.8 Sortieren von ganzzahligen Listen

Sortieren durch Mischen : Schema: sort(xs@ys) = merge(sort(xs),sort(ys))fun merge (nil,xs) = ys | merge (xs,nil) = xs | merge (x::xr,y::yr) = if x<=y then x::merge(xr,y:yr) else y::merge(x::xr,yr)fun split xs = foldl (fn (x,(ys,zs)) => (zs,x::ys)) (nil,nil) xsfun msort [ ] = [ ] | msort [x] = [x] | msort xs = let val (ys,zs) = split xs in merge(msort ys, msort zs) end

merge verschmilzt zwei sortierte Listen zu einer sortierten Liste.

split zerlegt eine Liste in zwei etwa gleichgrosse Teillisten.

msort realisiert Sortieren durch Mischen.

Programmierung 1 - Repetitorium

5.9 Polymorphe Sortierprozeduren

Die Sortierung ist immer abhängig von der gewählten Ordnung.Um Sortieren durch Einfügen polymorph zu schreiben, müssen wir einzusätzliches Argument einbinden, welches als Prozedur f die gewählteOrdnung entscheidet.

vordeklarierte polymorphe Sortierprozedur : Listsort.sort

vordeklarierte Ordnungen : Int.compare , Real.compare

fun pisort order = let fun insert (x,nil) = [x] | insert (x,y::yr) = if order(x,y) then x::y::yr else y::insert(x,yr) in foldl insert nil end

Typ : pisort : (‘a * ‘a → bool) → ‘a list → ‘a list