7 Imperatief Programmeren
7.1 Vectoren transformeren: vector-map!
Schrijf een procedure (vector-map! f vec), die een bestaande vector vec aanpast. De nieuwe elementen van deze vector worden berekend door de procedure f (die 1 argument neemt) uit te voeren op de originele elementen uit de vector vec.
> (define v (vector 1 2 3 4)) > (vector-map! (lambda (x) (* x x)) v) > v #(1 4 9 16)
7.2 Vectoren transformeren: vector-map
Schrijf een procedure (vector-map f vec), die een nieuwe vector teruggeeft. De elementen van de nieuwe vector worden berekend door de procedure f (die 1 argument neemt) uit te voeren op de overeenkomstige elementen uit de vector vec.
> (vector-map (lambda (x) (* x x)) (vector 1 2 3 4)) #(1 4 9 16)
7.3 Stukken uit een vector selecteren: vector-slice
Schrijf een procedure (vector-slice begin end vect) die een vector teruggeeft waarvan de elementen overeenkomen met de elementen op de posities begin t.e.m. end in de input-vector vect. Je mag ervan uitgaan dat end altijd groter of gelijk aan begin is.
> (vector-slice 2 6 (vector 0 1 2 3 4 5 6 7 8 9)) #(2 3 4 5 6)
> (vector-slice 3 3 (vector 0 1 2 3 4 5 6 7 8 9)) #(3)
> (vector-slice 4 5 (vector "the" "quick" "brown" "fox" "jumps" "over" "the" "lazy" "dog")) #("jumps" "over")
7.4 Vectoren aaneen plakken: vector-append
Schrijf een procedure vector-append om twee vectoren aaneen te plakken.
> (vector-append (vector 1 2 3) (vector 4 5 6 7)) #(1 2 3 4 5 6 7)
7.5 Voorspel het resultaat van expressies met destructieve operaties
Gegeven de definities:
(define x (list '(a b) '(c d))) (define y (cons x (cdr x)))
Voorspel dan het resultaat van de evaluatie (in volgorde) van volgende expressies (teken box-pointer diagrammen):
x
y
(car (car y))
(set-car! (car y) (cdr y))
x
y
7.6 Circulaire Datastructuren: make-ring!
Schrijf een functie (make-ring! n) die een positief geheel getal neemt en er een ring van maakt (een ring is een circulaire lijst van n tot 0).
De volgende hulpprocedure is een procedure die er (gelukkig) in slaagt een constructie met oneindige lussen op eindige manier af te drukken.
(define (print-ring r) (define (aux l) (if (not (null? l)) (cond ((eq? (cdr l) r) (display " ") (display (car l)) (display "...")) (else (display " ") (display (car l)) (aux (cdr l)))))) (aux r))
> (define r (make-ring! 3))
> (print-ring r) 3 2 1 0...
> (print-ring (cdr r)) 2 1 0 3...
7.7 Circulaire Datastructuren: shift-forward
Schrijf een procedure (shift-forward r) die een circulaire lijst 1 plaats voorwaarts verschuift.
> (define r (make-ring 3))
> (print-ring (shift-forward r)) 2 1 0 3...
7.8 Circulaire Datastructuren: shift-backward
Schrijf een procedure (shift-backward r) die een circulaire lijst 1 plaats achterwaarts verschuift.
> (define r (make-ring 3))
> (print-ring (shift-backward r)) 0 3 2 1...
7.9 Destructieve Procedures: map!
Schrijf een destructieve versie van map: (map! f lst) die een bestaande lijst aanpast (zonder nieuwe cons-cellen aan te maken).
De nieuwe elementen van deze lijst worden berekend door de functie f (die 1 argument neemt) uit te voeren op de originele elementen uit de lijst lst.
> (define l '(1 2 3 4)) > (map! (lambda (x) (* x x)) l) > l (1 4 9 16)
7.10 Destructieve Procedures: schuif-in!
Een procedure schuif-in! neemt als invoer twee lijsten en transformeert deze twee lijsten in 1 enkele lijst door afwisselend een element van de eerste en van de tweede lijst te nemen.
Schrijf nu een destructieve versie schuif-in! van de procedure. D.w.z. dat geen enkele nieuwe cons-cel mag aangemaakt worden. De procedure schuif-in! neemt als invoer de twee gegeven lijsten, en transformeert de eerste ervan op destructieve wijze in het gewenste resultaat.
> (define lijst1 '(1 3 5))
> (define lijst2 '(2 4 6 8))
> (schuif-in! lijst1 lijst2) ok
> lijst1 (1 2 3 4 5 6 8)
7.11 Destructieve Procedures: merge!
Reisbureau "Happy" en reisbureau "Tours" hebben besloten te fusioneren. Hiertoe moeten ze hun klantenbestanden samenvoegen. In beide gevallen wordt het klantenbestand voorgesteld door een geneste lijst, waarin van elke klant naam en adres wordt bijgehouden en die gesorteerd werd op naam. Bijvoorbeeld:
(define best1 '((ann (meiboomstraat 12 1820 Eppegem)) (bert (populierendreef 7 1050 Brussel)) (kurt (Mechelsesteenweg 50 1800 Vilvoorde)))) (define best2 '((bert (populierendreef 7 1050 Brussel)) (jan (eikestraat 1 9000 Gent)) (sofie (boerendreef 5 2800 Mechelen))))
Deze twee bestanden moeten samengevoegd worden tot een nieuwe gesorteerde geneste lijst, maar doordat zulke bestanden vrij groot kunnen zijn, moet dit destructief gebeuren. Bovendien kan het gebeuren dat sommige personen klant waren bij beide bureaus en dus reeds in de twee bestanden zitten.
7.11.1 Box-pointer diagram
Teken een box-pointer diagram van hoe je het probleem gaat aanpakken op het gegeven voorbeeld.
7.11.2 Samenvoegen van klantenbestanden
Schrijf een procedure (merge best1 best2) die de twee bestanden best1 en best2 destructief samenvoegt tot een nieuwe gesorteerde lijst. Hou rekening met de dubbels.
> (merge best1 best2)
((ann (meiboomstraat 12 1820 Eppegem))
(bert (populierendreef 7 1050 Brussel))
(jan (eikestraat 1 9000 Gent))
(kurt (Mechelsesteenweg 50 1800 Vilvoorde))
(sofie (boerendreef 5 2800 Mechelen)))
Je kan hiervoor gebruik maken van de volgende hulpprocedures:
(define (symbol<? s1 s2) (string<? (symbol->string s1) (symbol->string s2))) (define (element=? el1 el2) (equal? el1 el2))
7.12 Extra Oefeningen
7.12.1 Copy ring
Schrijf een functie copy-ring die een kopie van een circulaire lijst teruggeeft.
> (define r (make-ring 3))
> (define s (copy-ring r))
> (print-ring s) 3 2 1 0...
> (set-car! s 999)
> (print-ring s) 999 2 1 0...
> (print-ring r) 3 2 1 0...
> (set-car! (cdr s) 888)
> (print-ring s) 999 888 1 0...
> (print-ring r) 3 2 1 0...
7.12.2 Het Josephus probleem
Schrijf een functie (josephus r n) die een circulaire lijst afloopt en telkens het n-de element verwijdert, totdat er slechts 1 element over is. Dat laatste wordt als resultaat teruggegeven. Je mag procedures gebruiken die we hierboven gedefinieerd hebben.
> (define ring (make-ring 5))
> (josephus ring 5) 5 4 3 2 1 0... 0 5 4 3 2... 0 5 4 3... 5 4 3... 3 5... 5...
5
> (print-ring ring) 5 4 3 2 1 0...
7.12.3 Neveneffecten bij append
Als je weet dat append in Scheme gedefinieerd is zoals hieronder, en met de volgende definities voor l1, l2 en l3:
(define (append x y) (cond ((null? x) y) (else (cons (car x) (append (cdr x) y)))))
(define l1 '(1 2 3)) (define l2 '(4 5)) (define l3 (append l1 l2))
Voorspel dan de waarden van l1, l2 en l3 na evaluatie van elk van de volgende expressies:
> (set-car! l1 6) l1
l2
l3
> (set-car! (cdr l3) 7) l1
l2
l3
> (set-car! (cdr l2) 8) l1
l2
l3
> (set-car! (cdddr l3) 9) l1
l2
l3
7.12.4 Examen Wiskunde 1ste zit 1994
Schrijf een destructieve procedure (kw-lijst lst) die een circulaire lijst omvormt tot een circulaire lijst met twee keer zoveel elementen, door vlak na ieder element van de lijst een nieuw element tussen te voegen waarvan de waarde gelijk is aan het kwadraat van het oorspronkelijke element. Bijvoorbeeld, de lijst met box-pointer diagram
wordt omgevormd tot de volgende circulaire lijst:
> (define last-cons (cons 3 '()))
> (define test-lst (cons 1 (cons 4 last-cons)))
> (set-cdr! last-cons test-lst)
> (print-ring (kw-lijst test-lst)) 1 1 4 16 3 9...
7.12.5 Examen Informatica 1ste zit 1996
Schrijf een destructieve procedure ontdubbel! die een (platte) lijst van getallen als invoer neemt, en een cons-cel teruggeeft met als car de lijst van alle even elementen van de oorspronkelijke lijst, en als cdr de lijst van alle oneven elementen van de oorspronkelijke lijst. Bovendien is dit de enige(!) nieuwe cons-cel die je procedure mag aanmaken. Let ook op dat de onderliggende volgorde der elementen behouden blijft.
> (ontdubbel! '(1 2 3 4 5 6 7 8 9 10)) ((2 4 6 8 10) 1 3 5 7 9)
7.12.6 Examen januari 2004: Destructief
Schrijf destrucief een functie (insert! lst1 lst2) die twee lijsten lst1 en lst2 als parameter neemt. De lijst lst1 is een lijst van (niet lege!) lijstjes, de lijst lst2 is een lijst met symbolen. De functie insert! voegt de symbolen van lst2 toe aan de achterkant van de lijstjes in lst1.
Hou er rekening mee dat je geen enkele nieuwe cons-cel mag aanmaken! Je mag alleen maar bestaande cons-cellen wijzigen. Je mag ervan uitgaan dat de lijstjes lst1 en lst2 even lang zijn.
> (insert! '((a 12 q) (b 13) (c 14 r s) (f 18) (j 22 t)) '(v w x y z)) ((a 12 q v) (b 13 w) (c 14 r s x) (f 18 y) (j 22 t z))
7.12.7 Examen januari 2008: Destructief
Schrijf een destructieve procedure all-but-interval die een stijgend geordende lijst van getallen neemt en alle getallen in een gegeven interval verwijdert. Er worden twee parameters doorgegeven om het interval aan te duiden, en de eerste is kleiner of gelijk aan de tweede.
> (all-but-interval '(1 2 3 4 5 6) 2 4) (1 5 6)
> (all-but-interval '(1 2 3 4 5) 2 2) (1 3 4 5)
> (all-but-interval '(1 2 5 6 7) 3 9) (1 2)