HW 04

Higher Level Functions

Due at 6PM on Tuesday, March 13

The goal for this assignment is to give you a deeper understanding of recursion, particularly on complex structures

Part 1: Fold

In each of the following you can use either of the folds we have discussed: foldl or foldr

  1. Use fold to write (index a lat), which returns the 0-based index of atom a in lat, or -1 if a is not an element of lat.

  2. Use fold to write (replace a b lat), which replaces every instance of atom a with atom b. For example (replace 3 5 '(1 2 3 4 5 4 3 2 1)) returns (1 2 5 4 5 4 5 2 1).

  3. Assume bags is globally defined to be an association list containing sublists of two elements. Each sublist represents the name of a piece of luggage and its respective weight, where the car is the name of the piece of luggage and the cadr is the weight. Such a list might look like this:
                          (define bags '((duffle 8) (garment-bag 2) (briefcase 5) (valise 7) (steamer-trunk 65))).
    1. Use fold to write a procedure (weigh bags) which takes a baggage list and returns the total weight. For the baggage list shown above this should return 87.
    2. Use fold to write a procedure (heaviest bags) which returns the name of the bag with maximum weight. Assume that no weights are negative. For the baggage list above this should return 'steamer-trunk.

Part 2: Trees

For the rest of this assignment you will write a number of procedures that involve trees. Recall that a tree is a data structure that is either empty, or contains some data and has a list of children, each of which is a tree.

We will use Scheme procedures to implement the data type. At the beginning of the following section the tree datatype will be defined. All of this code is contained in the file "TreeDatatype.rkt".

#lang racket
(require "TreeDatatype.rkt")

You will need to download the file TreeDatatype.rkt Please include this file in your handin folder.

Introduction -- the tree structure

A tree is either

  1. an empty tree, which has no fields
  2. a non-empty tree, which has a value field containing a number and a list-of-children field containing a list of children of the node, which are themselves trees.

(define tree? (lambda (t) (or (empty-tree? t) (non-empty-tree? t))))

(define empty-tree? (lambda (x) (null? x)))

(define non-empty-tree? (lambda (x)
                       [(list? x) (eq? (car x) 'tree)]
                       [else #f])))

; constructors
(define non-empty-tree (lambda (value list-of-children)
             (list 'tree value list-of-children)))

(define empty-tree (lambda () null))

; Convenience constructor
(define makeTree (lambda l
              (non-empty-tree (car l) (cdr l))))

; utility functions
(define value (lambda (tree)
                       [(empty-tree? tree) 'error]
                       [else (cadr tree)])))

(define list-of-children (lambda (tree)
                       [(empty-tree? tree) 'error]
                       [else (caddr tree)])))

(define number-of-children (lambda (tr)
                       [(empty-tree? tree) 'error]
                       [else (length (list-of-children tr))])))

(define leaf? (lambda (tr)
                       [(empty-tree? tree) 'error]
                       [else (zero? (number-of-children tr))])))

; example trees

(define Empty (empty-tree))
(define T1 (makeTree 50))
(define T2 (makeTree 22))
(define T3 (makeTree 10))
(define T4 (makeTree 5))
(define T5 (makeTree 17))
(define T6 (makeTree 73 T1 T2 T3))
(define T7 (makeTree 100 T4 T5))
(define T8 (makeTree 16 T6 T7))


For example, here is a picture of T8 showing the others as subtrees:


We can view T8 as a list: (16 (73 (50) (22) (10)) (100 (5) (17))). Be sure that you can see how the tree structure is preserved in this list.

All of this code is in file TreeDatatype.rkt

In the exercises that follow, you should use higher-order functions like map, apply, and fold to make your solution as concise as possible. You should also use letrecto define any recursive help functions.

All programs should be written using the tree operators defined above. Don't directly manipulate the list representations; use the tree procedures.

As usual, if the solution to an earlier problem is useful in a later one, go ahead and use it.

Tree Exercises:

In all of these tr is a value of the tree datatype

  1. (childSum tr) This returns the sum of the values in the children of the given node. The tree is assumed to be non-empty.
    (childSum T8) returns 173;
    (childSum T6) returns 82.

  2. (allSum tr) This sums the entire set of values found in the tree. If tree is empty it returns 0.
    (allSum T8) is 293
    (allSum T6) is 155

  3. (visitTree f tr) Here f is a function of 1 numerical variable. This returns a new tree with the same structure only every value v in tree has been transformed to (f v).

  4. (sizeof tr) This returns the number of nodes in the subtree rooted at the given node.
    (sizeof T8) returns 8
    (sizeof T6) retrurns 4

  5. (height tr) Returns the height of the tree -- the maxiumum number of edges from root to leaf.. Assume that the empty tree has height -1, a single-node tree (a leaf) has height 0, etc.
    (height T1) returns 0
    (height T8) returns 2

  6. (count n tr) Returns the number of times value n appears in the tree.
    (count 22 T8) returns 1
    (count 7 T8) returns 0

  7. Each of the next two procedures produces a flat list of the values in the tree. They differ only in the order in which the values are listed:

  8. (preorder tr) lists the value at the root ahead of the values of the children. 
     (preorder T8) returns (16 73 50 22 10 100 5 17)

  9. (postorder tr) lists the value at the root after the values of the children. 
      (postorder T8) returns (50 22 10 73 5 17 100 16)