html5-img
1 / 47

1321

1321. CS. CS1321: Introduction to Programming. Georgia Institute of Technology College of Computing Lecture 13 October 4, 2001 Fall Semester. Today’s Menu. Lists in Lists: Applying the concept of trees to non-trees… 2. Cross-Referencing your structures. a. b. c. d. e. g. f.

mina
Télécharger la présentation

1321

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 1321 CS

  2. CS1321:Introduction to Programming Georgia Institute of Technology College of Computing Lecture 13 October 4, 2001 Fall Semester

  3. Today’s Menu • Lists in Lists: Applying the concept of trees to non-trees… • 2. Cross-Referencing your structures.

  4. a b c d e g f Last time… We explored the concept of trees and types of trees in greater detail. We talked a little bit about how dealing with the data inside of trees was a more complex process than dealing with data in a “flat” data structure such as a list…

  5. empty 2 3 1 Why was that? In a list, we recur down a single path. We commonly deal with that by doing something similar to the following: ( + (first my-list) (recursive-call (rest my-list)))

  6. empty 2 3 1 Why was that? In a list, we recur down a single path. We commonly deal with that by doing something similar to the following: ( + (first my-list) (recursive-call (rest my-list))) We deal with each item in the list linearly, moving from one item to the next in our recursive call until we reach a terminating condition.

  7. 30 18 60 2 1 55 7 10 50 But in trees… We don’t have that nice, linear structure to follow as we try to deal with our information. We have branches, and we have to follow those branches as the problem requires. ( + (node-data my-tree) (recursive-call (node-left my-tree)) (recursive-call (node-right my-tree)))

  8. We gave this type of branching recursion a name… We called it tree recursion. After all, we were using it to manipulate values in a tree structure. You may have the impression that tree recursion was only for trees. But is that the case?

  9. As it turns out… Tree recursion doesn’t just deal with trees. It’s very useful when dealing with our trees of varying shapes and sizes, from binary to n-ary trees… But we can also create other examples where this concept of joining together different branches of recursive calls is particularly useful. Such as…

  10. List of Lists… ;; a nested-list-of-numbers is either: ;; 1) the empty list, empty, ;; 2) (cons n nlon) where n is a number and nlon is ;; nested-list-of-numbers, or ;; 3) (cons data-nlon nlon) where data-nlon and ;; nlon are both nested-list-of-numbers

  11. Pictorially… e 4 6 7 e 3 e e 16 4 7 12 e For the sake of space “e” stands for empty 8

  12. e 4 6 7 3 e e 16 4 7 12 e 8 Pictorially… Or using short-hand: ‘((3 (16) 8) 4 (4 7 12) 6 7)

  13. What would this do to our template? Just as when we created our “shape” definition, we just add more conditions to the cond statement: (define (process-nlon my-nlon) (cond ((empty? my-nlon) …) ((list? (first my-nlon)) …(first my-nlon) …(process-nlon (rest my-nlon))) (else …(first my-nlon) …(process-nlon (rest my-nlon)))))

  14. What would this do to our template? But wait….we didn’t do anything different if our first item was in fact a nested-list of numbers… Shouldn’t we process that first nested list? Just as when we created our “shape” definition, we just add more conditions to the cond statement: (define (process-nlon my-nlon) (cond ((empty? my-nlon) …) ((list? (first my-nlon)) …(first my-nlon) …(process-nlon (rest my-nlon))) (else …(first my-nlon) …(process-nlon (rest my-nlon)))))

  15. Tree Recursion on lists… ((list? (first my-nlon)) …(process-nlon (first my-nlon)) …(process-nlon (rest my-nlon))) (else …(first my-nlon) …(process-nlon (rest my-nlon))))) Chances are, we do want to process the nested list. So we add another recursive call… See the two recursive calls even under one question of the cond? That is what makes this “tree recursion” (more than one recursive call so we handle both branches in this case.)

  16. ((list? (first my-nlon)) …(process-nlon (first my-nlon)) …(process-nlon (rest my-nlon))) What we are doing in this example is “branching” our recursion down the new path that we’ve found in our list. Much as we “branched” down each of the paths in our tree example… After all…

  17. We could just “rotate” our nested list a little…

  18. We could just “rotate” our nested list a little… And it even looks like a tree!

  19. So thinking through a problem… Your boss decides one day that he doesn’t like nested lists of numbers. He’d rather just deal with flat, one level list of numbers instead. Write a function called flatten that consumes a nested-list-of-numbers and returns a normal list-of-numbers (as we defined many times in the past few weeks).

  20. Before we begin… We need to introduce a scheme function that will be absolutely essential to our flatten function: (append <list 1> <list 2>) takes in a list 1 and a list 2 and appends (adds) all the items from the second list to the end of list 1. (append empty empty)  empty (append ‘(1 2 3) empty)  (list 1 2 3) (append empty ‘(4 5 6))  (list 4 5 6) (append ‘(1 2 3) ‘(4 5 6))  (list 1 2 3 4 5 6)

  21. Append Note: In every case, append takes lists as parameters! (It cannot be used directly to add a number or a symbol for example to a list.) It is used to put two lists together forming one list. (append <list 1> <list 2>) takes in a list 1 and a list 2 and appends (adds) all the items from the second list to the end of list 1. (append empty empty)  empty (append ‘(1 2 3) empty)  (list 1 2 3) (append empty ‘(4 5 6))  (list 4 5 6) (append ‘(1 2 3) ‘(4 5 6))  (list 1 2 3 4 5 6)

  22. Let’s start with our template… (define (process-nlon my-nlon) (cond ((empty? my-nlon) …) ((list? (first my-nlon)) …(process-nlon (first my-nlon)) …(process-nlon (rest my-nlon))) (else …(first my-nlon) …(process-nlon (rest my-nlon)))))

  23. Fill in the easy parts… (define (flatten my-nlon) (cond ((empty? my-nlon) empty) ((list? (first my-nlon)) …(flatten (first my-nlon)) …(flatten (rest my-nlon))) (else …(first my-nlon) …(flatten (rest my-nlon)))))

  24. What do we want back from flatten? A flat list of numbers. In the cond under list? we have two calls to flatten. We produce two flat list of numbers; how do we join them into one list?? (define (flatten my-nlon) (cond ((empty? my-nlon) empty) ((list? (first my-nlon)) …(flatten (first my-nlon)) …(flatten (rest my-nlon))) (else …(first my-nlon) …(flatten (rest my-nlon)))))

  25. (define (flatten my-nlon) (cond ((empty? my-nlon) empty) ((list? (first my-nlon)) (append (flatten (first my-nlon)) (flatten (rest my-nlon)))) (else …(first my-nlon) …(flatten (rest my-nlon))))) We use append.

  26. (define (flatten my-nlon) (cond ((empty? my-nlon) empty) ((list? (first my-nlon)) (append (flatten (first my-nlon)) (flatten (rest my-nlon)))) (else …(first my-nlon) …(flatten (rest my-nlon))))) Shouldn’t we do something similar for this case?

  27. (define (flatten my-nlon) (cond ((empty? my-nlon) empty) ((list? (first my-nlon)) (append (flatten (first my-nlon)) (flatten (rest my-nlon)))) (else (append (first my-nlon) (flatten (rest my-nlon)))))) Shouldn’t we do something similar for this case? Is that okay?

  28. (define (flatten my-nlon) (cond ((empty? my-nlon) empty) ((list? (first nlon)) (append (flatten (first nlon)) (flatten (rest my-nlon)))) (else (append (first nlon) (flatten (rest my-nlon)))))) This the case where the first item is not a list. Append won’t work! (needs lists!) Unless…

  29. (define (flatten my-nlon) (cond ((empty? my-nlon) empty) ((list? (first my-nlon)) (append (flatten (first my-nlon)) (flatten (rest my-nlon)))) (else (append (list (first my-nlon)) (flatten (rest my-nlon)))))) We make the first item a list itself!

  30. And so… (define (flatten my-nlon) (cond ((empty? my-nlon) empty) ((list? (first my-nlon)) (append (flatten (first my-nlon)) (flatten (rest my-nlon)))) (else (append (list (first my-nlon)) (flatten (rest my-nlon)))))) Note: we could have used cons just now…

  31. And so… (define (flatten my-nlon) (cond ((empty? my-nlon) empty) ((list? (first my-nlon)) (append (flatten (first my-nlon)) (flatten (rest my-nlon)))) (else (cons (first my-nlon) (flatten (rest my-nlon)))))) Note: Version using cons to deal with first being a non-list (the last case of the cond.)

  32. Let’s run both in DrScheme!

  33. Cross-Referencing your Structures… Our data definitions are getting more complex. We just worked with a list that could contain as its data other lists. What if we made things even more complex?

  34. The Family Tree, take two… Last time we considered the problem of a family tree, we defined it from our particular viewpoint. That is to say, we started with ourselves, and traced our lineage backwards through time. This fit quite nicely into the idea of a binary tree. After all, you’ll never have more than two biological parents….

  35. But from the other direction… But what if we don’t want to go backwards through time, but instead go forward and trace a particular person’s descendents? Let’s see if we can start as before and fit our definition into something that looks like a binary tree…

  36. The Parent What are some properties of a parent? 1) They have a name 2) They have a year that they were born 3) They have an eye color So far nothing different from how we defined a child in lecture 11.

  37. 4) A parent has children. Ooops. Here is a difference. Before we were able to assumethat a child has no more than two biological parents. But how many children will a parent have? Can we limit ourselves to one, or two, or five?

  38. Nope… We can’t limit a parent to a certain number of children. It varies from no children to some unknown number of children. Each parent has a different number. (Note: We are using the notion of “parent” to even include those with no children… Bear with me on the terminology.) Our binary tree model no longer works! So how can we fix our definition?

  39. The new data definition… (define-struct parent (name born eyes children)) ;;A parent is a structure: ;; (make-parent n b e loc) ;;Where n & e are symbols, b is a number, and loc is a ;;list-of-children What’s a list-of-children?

  40. ;; a list-of-children is either: ;; 1) the empty list, empty ;; 2) (cons p loc) where p is a parent and loc is ;; a list-of-children

  41. ;; a list-of-children is either: ;; 1) the empty list, empty ;; 2) (cons p loc) where p is a parent and loc is ;; a list-of-children Remember, we’re creating an “ancestor” family tree. So every child of a previous generation will also be the parent of the next generation

  42. So all together… (define-struct parent (name born eyes children)) ;;A parent is a structure: ;; (make-parent n b e loc) ;;Where n & e are symbols, b is a number, and loc is a ;;list-of-children ;; a list-of-children is either: ;; 1) the empty list, empty, or ;; 2) (cons p loc) where p is a parent and loc is ;; a list-of-children

  43. So all together… (define-struct parent (name born eyes children)) ;;A parent is a structure: ;; (make-parent n b e loc) ;;Where n & e are symbols, b is a number, and loc is a ;;list-of-children ;; a list-of-children is either: ;; 1) the empty list, empty ;; 2) (cons p loc) where p is a parent and loc is ;; a list-of-children

  44. What we’ve created… Are mutually referential data definitions. These two definitions refer to each other in their bodies. Which of course has implications for our template…

  45. As we have two data definitions, we really need to have two different templates, one for each: (define (process-parent in-parent) …(parent-name in-parent)… …(parent-born in-parent)… …(parent-eyes in-parent)… …(parent-children in-parent)…) (define (process-loc in-loc) (cond ((empty? in-loc) …) (else …(first in-loc)… …(process-loc (rest in-loc))…)))

  46. As we have two data definitions, we really need to have two different templates, one for each: (define (process-parent in-parent) …(parent-name in-parent)… …(parent-born in-parent)… …(parent-eyes in-parent)… …(parent-children in-parent)…) (define (process-loc in-loc) (cond ((empty? in-loc) …) (else …(first in-loc)… …(process-loc (rest in-loc))…))) Why don’t we call each template function from within the other?

  47. Once again… The template not only reflects the data definition, but it also describes the generic case. It may not be the case that we’re necessarily going to call the process-parent function as we traverse a list of children. We may just want to count children. Or if we’re dealing with a parent structure, we may not wish to actually traverse the list of children. The template is generic. It’s up to you to build your function definition using it based on what you need to solve your specific problem.

More Related