Presentation is loading. Please wait.

Presentation is loading. Please wait.

Class 11: Two-argument recursion

Similar presentations


Presentation on theme: "Class 11: Two-argument recursion"— Presentation transcript:

1 Class 11: Two-argument recursion
Almost every procedure today will work on int-lists An int-list is either empty, or (cons item lst), where item is an int and lst is an int-list. Nothing else is an int-list. [Now we don't need to do that part of the design recipe] Examples (define ex0 empty) (define ex1 (list 1 3)) (define ex2 (list 1 4 7)) (define ex3 (list 2 4 9)) Most procedures will use two arguments

2 Warmup: two argument recursion, list + atomic
We wrote "improve", which converted (list ) to (list ) Recursive diagram: Orig. in.: (list ) Rec. In: (list 7 10) Rec. out: (list 17 17) Cons on a 17 to the recursive output? Orig out (list )

3 Warmup: two argument recursion, list + atomic
We wrote "improve", which converted (list ) to (list ) Code: (define (improve aloi) (cond [(empty? aloi) empty] [(cons? aloi) (cons 17 (improve (rest aloi)))]))

4 New: (better num aloi) Better produces a new list of the same length as aloi, but with each item replaced with "num: (better (list ) 14) produces (list ) Recursive diagram: Orig. in.: (list ), 14 Rec. In: (list 7 10), 14 Rec. out: (list 14 14) Cons on a "num" to the recursive output? Orig out: (list )

5 New: (better num aloi) Better produces a new list of the same length as aloi, but with each item replaced with "num: code (define (better num aloi) (cond [(empty? aloi) empty] [(cons? aloi) (cons num (better (rest aloi)))]))

6 General rules for natural num* list recursion
Recursive input is often the same natnum, and "rest" of the list Alternatives: reduce natnum by 1, keep the list the same; base case is when natnum is zero reduce natnum by 1, take "rest" of the list. reduce natnum by 1, somehow enlarge this list Example of case 2: to find the nth item in a list (of at least n items)… find the n-1st item in the rest of the list! This weekend's lab: natural-number recursion

7 Generalities More arguments means more complexity
More arguments means more things you might recur on…and just about any possibility might arise. More arguments means more structures in the main "cond": empty, empty cons, empty empty, cons cons, cons For two-list recursion, three main possibilities Illustrate one with a first example: all-matches

8 Example proc: "all-matches"
; all-matches: (int list) * (int list) -> (int list) ; Input: lists aloi and aloi2, of the same length ; Output: a list consisting of items that "match" in corresponding locations in the two input lists. (check-expect (all-matches (list 1 2 5) (list 1 3 5)) (list 1 5)) (check-expect (all-matches (list 1 2 5) (list 2 4 6)) empty) (check-expect (all-matches empty empty) empty) (check-expect (all-matches (list 4) (list 4)) (list 4))

9 Decision time: on which input(s) to recur?
Original inputs: (list 1 2 5) (list 1 3 5) Recursive inputs: ??? ??? Recursive result: Original result: (list 1 5)

10 Decision time Original inputs: (list 1 2 5) (list 1 3 5)
; Input: lists aloi and aloi2, of the same length Original inputs: (list 1 2 5) (list 1 3 5) Recursive inputs: ??? ??? Three basic choices Shorten the first list; leave other unchanged Shorten the second list; leave first unchanged Shorten both lists More exotic choice Shorten first list, lengthen the second (!) Base case: first list is empty (but second could be huge!) For this problem: which one? Shorten both; otherwise recursive input doesn't meet input spec (equal-length lists)

11 Decision time Original inputs: (list 1 2 5) (list 1 3 5) Recursive inputs: (list 2 5) (list 3 5) Recursive result: (list 5) Original result: (list 1 5)

12 Flesh out recursive diagram
Original inputs: (list 1 2 5) (list 1 3 5) Recursive inputs: (list 2 5) (list 3 5) Recursive result: (list 5) Cons a 1 onto the recursive result? Cons (first aloi) onto recursive result? Original result: (list 1 5) Time to draw another example!

13 Flesh out recursive diagram
Original inputs: (list 1 2 5) (list 2 3 5) Recursive inputs: (list 2 5) (list 3 5) Recursive result: (list 5) Cons a 1 onto the recursive result? NO! Cons (first aloi) onto recursive result? NO! Cons (first aloi) onto recursive result ONLY if the two "firsts" match? Yes! Original result: (list 5)

14 Write the call-structure and template
(define (all-matches aloi aloi2) (cond [??? Wait…what are the possible kinds of input? Each of aloi and aloi2 could be empty or cons!

15 Write the call-structure and template
(define (all-matches aloi aloi2) (cond [(and (empty? aloi) (empty? aloi2)) …] [(and (empty? aloi) (cons? aloi2)) …] [(and (cons? aloi) (empty? aloi2)) …] [(and (cons? aloi) (cons? aloi2)) …])) For our particular procedure, where the lengths must be the same, two of these never occur

16 Write the call-structure and template
(define (all-matches aloi aloi2) (cond [(and (empty? aloi) (empty? aloi2)) …] [(and (cons? aloi) (cons? aloi2)) …])) What goes in the … places? For the first, the base case For the second, something involving first and rest of the two lists The "rests" are involved in a recursive call (because of our diagram)

17 Write the code! (define (all-matches aloi aloi2) (cond [(and (empty? aloi) (empty? aloi2)) …] [(and (cons? aloi) (cons? aloi2)) ... (first aloi) … (first aloi2) … (all-matches (rest aloi) (rest aloi2))])) Cons (first aloi) onto recursive result ONLY if the two "firsts" match? Yes! Work with your neighbor to fill in the second case. (The first is empty)

18 Write the code! (define (all-matches aloi aloi2) (cond [(and (empty? aloi) (empty? aloi2)) empty] [(and (cons? aloi) (cons? aloi2)) (if (= (first aloi) (first aloi2)) (cons (first aloi) (all-matches (rest aloi) (rest aloi2))) (all-matches (rest aloi) (rest aloi2)))]))

19 New Problem! Which list is longer?
; Input: two int lists aloi1 and aloi2 ; Output: a boolean, true if aloi1 is longer than aloi2, ; false if they're the same length or aloi2 is longer. (define (longer? aloi1 aloi2) …) Test cases?

20 Which list is longer? ; Input: two int lists aloi and aloi2 ; Output: a boolean, true if aloi is longer than aloi2, ; false if they're the same length or aloi2 is longer. (define (longer? aloi aloi2) …) (check-expect (longer? (list 1 2 5) (list 1 3)) true) (check-expect (longer? (list 1 2) (list 2 4 6)) false) (check-expect (longer? empty empty) false) (check-expect (longer? (list 4) empty) true) (check-expect (longer? empty (list 4)) false)

21 Decision time Original inputs: (list 1 2 5) (list 1 3) Recursive inputs: ??? ??? Recursive result: ??? Original result: true  could shorten one list, the other, or both!

22 Decision time Original inputs: (list 1 2 5) (list 1 3) Recursive inputs: (list 2 5) (list 3) Recursive result: true Copy recursive result? Original result: true

23 Decision time Original inputs: (list 1 2) (list 2 4 6) Recursive inputs: (list 2) (list 4 6) Recursive result: false Copy recursive result? Original result: false

24 Another diagram! Original inputs: (list 4) , empty Recursive inputs: empty, NA Recursive result: This must be another base case! If first list empty: false If both empty: false If first cons, second empty: true Otherwise recur on both and copy recursive result Original result: true

25 Which list is longer? Template? ; Input: two int lists aloi1 and aloi2
; Output: a boolean, true if aloi1 is longer than aloi2, ; false if they're the same length or aloi2 is longer. (define (longer? aloi1 aloi2) …) (check-expect (longer? (list 1 2 5) (list 1 3)) true) (check-expect (longer? (list 1 2) (list 2 4 6)) false) (check-expect (longer? empty empty) false) (check-expect (longer? (list 4) empty) true) (check-expect (longer? empty (list 4)) false) Template?

26 Which list is longer? ; Input: two int lists aloi1 and aloi2
; Output: a boolean, true if aloi1 is longer than aloi2, ; false if they're the same length or aloi2 is longer. (define (longer? aloi1 aloi2) (cond [(and (empty? aloi1) (empty? aloi2)) …] [(and (cons? aloi1) (empty? aloi2)) … (first aloi1)… (rest aloi1) … ] [(and (empty? aloi1) (cons? aloi2)) … (first aloi2)… (rest aloi2) … ] [(and (cons? aloi1) (cons? aloi2)) … (first aloi1)… (rest aloi1) … (first aloi2)… (rest aloi2) … ] there's likely to be a recursive call in the last line, and possibly the two before it.

27 Fill in ; Input: two int lists aloi1 and aloi2 ; Output: a boolean, true if aloi1 is longer than aloi2, ; false if they're the same length or aloi2 is longer. (define (longer? aloi1 aloi2) (cond [(and (empty? aloi1) (empty? aloi2)) false] [(and (cons? aloi1) (empty? aloi2)) true] [(and (empty? aloi1) (cons? aloi2)) false] [(and (cons? aloi1) (cons? aloi2)) (longer? (rest aloi1) (rest aloi2))]))

28 A racket built-in (which you'll be writing for HW)
(member item lst): true if item is in the list; false otherwise. Let's use this to write "intersect", which takes two lists and produces a list of things that are in both. ;; intersect: (int list) * (int list)-> (int list) ;; input: alod1, a list of ints ;; alod2, another list of ints ;; output: a list that’s identical to alod1, except that items not in alod2 ;; are deleted. In short, elements in both alod1 and alod2.

29 Recursive diagram Original inputs: (list 1 2 5) (list 1 3 2) Recursive inputs: (list 2 5) (list 1 3 2) Recursive result: (list 2) cons 1 (i.e., (first aloi)) onto the result because 1 is in (list 1 3 2); if it were not, we'd just return the recursive result Original result: (list 1 2)

30 Here member served as a helper procedure
;; intersect: (int list) * (int list)-> (int list) ;; input: alod1, a list of ints ;; alod2, another list of ints ;; output: a list that’s identical to alod1, except that items not in alod2 ;; are deleted. In short, elements in both alod1 and alod2. (define (intersect? aloi aloi2) (cond [(and (empty? aloi) (empty? aloi2)) empty] [(and (cons? aloi) (empty? aloi2)) empty] [(and (empty? aloi) (cons? aloi2)) empty] [(and (cons? aloi) (cons? aloi2)) (if (member (first aloi) aloi2) (cons (first aloi) (intersect (rest aloi) (rest aloi2))) (intersect (rest aloi) (rest aloi2)))])) Here member served as a helper procedure You'll often want to write your own helpers Mention that "member" here is like cons, in being a builtin…but since you could have written it (and will) it's a little different, too.

31 One more challenge: list reversal
Define the problem by examples, for expedience: (check-expect (my-reverse (list 1 2 3)) (list 3 2 1)) (check-expect (my-reverse empty) empty) (check-expect (my-reverse (list 1)) (list 1))

32 ;; my-reverse: (int list) -> (int list) ;; input: alod, a list of ints ;; ;; output: a list that’s contains the same items as alod, ;; but in reverse order (check-expect (my-reverse (list 1 2 3)) (list 3 2 1)) (check-expect (my-reverse empty) empty) (check-expect (my-reverse (list 1)) (list 1))

33 Recursive diagram Original input: (list 1 2 5) Recursive inputs: (list 2 5) Recursive result: (list 5 2) Stick (first aloi) on as the last item in the list? Could write a helper to do this… Original result: (list 5 2 1)

34 Bad idea This approach to reversing a list ends up being slow and complicated Turns out there's an easier way Involves generalizing the problem Oddly, in CS, sometimes it's easier to solve a more general problem than a more specific one! Finding the right "generalized problem" requires insight and experience, alas.

35 Reverse-with-tail > (reverse-with-tail (list 1 2 3) (list 4 5)) (list ) > (reverse-with-tail (list 1 2 3) empty) (list 3 2 1) ;; reverse-with-tail: (int list) * (int list) -> (int list) ;; input: aloi, a list of integers ;; tail, another list of integers ;; output: the elements of aloi, in reverse order, followed by ;; those of tail, in their original order

36 Why is this a good idea? If we can write reverse-with-tail, then reverse becomes easy: (define (reverse aloi) (reverse-with-tail aloi empty))

37 Recursive diagram Original input: (list 1 2 5) (list 3 4) Recursive inputs: (list 2 5) ??? Recursive result: (list ) just copy the recursive result! Original result: (list )

38 Big idea from aloi, tail, recur to (rest aloi), (cons (first aloi) tail) First list gets shorter, so we eventually hit a base case (first list empty) Second list grows!

39 code! (define (reverse-with-tail aloi tail) (cond [(and (empty? aloi) (empty? tail)) empty] [(and (empty? aloi) (cons? tail)) tail] [(and (cons? aloi) (empty? tail)) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))] [(and (cons? aloi) (cons? tail)) (cons (first aloi) tail)))]))

40 Simplify (define (reverse-with-tail aloi tail) (cond [(and (empty? aloi) (empty? tail)) empty] [(and (empty? aloi) (cons? tail)) tail] [(and (cons? aloi) (empty? tail)) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))] [(and (cons? aloi) (cons? tail)) (cons (first aloi) tail)))]))

41 Simplify (define (reverse-with-tail aloi tail) (cond [(and (empty? aloi) (empty? tail)) empty] [(and (empty? aloi) (cons? tail)) tail] [(cons? aloi) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))]))

42 Simplify (define (reverse-with-tail aloi tail) (cond [(and (empty? aloi) (empty? tail)) empty] [(and (empty? aloi) (cons? tail)) tail] [(cons? aloi) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))]))

43 Simplify (define (reverse-with-tail aloi tail) (cond [(and (empty? aloi) (empty? tail)) tail] [(and (empty? aloi) (cons? tail)) tail] [(cons? aloi) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))]))

44 Simplify (define (reverse-with-tail aloi tail) (cond [(empty? aloi) tail] [(cons? aloi) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))]))

45 Simplify (define (reverse-with-tail aloi tail) (cond [(empty? aloi) tail] [(cons? aloi) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))]))


Download ppt "Class 11: Two-argument recursion"

Similar presentations


Ads by Google