ICS H21 • UC IRVINE • DAVID G. KAY • FALL 2009

Lab Assignment 5


This assignment is due at the end of lab on Friday, October 30.

Choose a partner for this assignment, someone you haven't worked with already. Starting with this assignment, change your language level to Intermediate Student with Lambda.

(a) In class, we did an "inorder traversal" of a BST, the equivalent of exercise 14.2.3; we called it BST->list. (Note that the textbook arranges their trees a little differently, with an empty node as false where we used empty. Either way works, so long as you stick to one way consistently. Also, each node in their trees has two value fields, a number and a name, rather than just the single number we used.) We also did the insertion of an item into a BST, the equivalent of exercise 14.2.5; we called it BST-insert. And we wrote a function to take a list of items and insert each item into a BST, the equivalent of exercise 14.2.6; we called it list->BST. You should know how to recognize these functions and how to write them.

In class we did not write a function to search for an item in a binary tree, the equivalent of exercise 14.2.4. So we'll give you a chance to do it now. Write the function BST-member? as described below. Write it to process BSTs as we defined them in class (rather than as described in the book).

;; BST-member?: number  BST  ->  boolean
;; Return true if number appears in BST and false otherwise
(check-expect (BST-member? 17 empty) false)
(check-expect (BST-member? 17 (list->BST (list 17))) true)
(check-expect (BST-member? 17 (list->BST (list 34 43 28 16 17 24 134 34))) true)
(check-expect (BST-member? 17 (list->BST (list 34 3 23 2 25 26 24))) false)

Here are some hints if you'd like them: You have the contract, purpose statement, and examples above. Next, write the function header (define and lambda). Since a tree is either empty or not, have a cond to distinguish. Now, what do you return if the tree's empty? If it's not empty, what two things do you have to look at? What if they're equal, what do you return? If they're not equal, you're going to have to keep looking (recursively) in either the left subtree or the right subtree; how do you decide which?

Submit your definitions via Checkmate.

(b) Do exercises 14.3.2, 14.3.3, and 14.3.4 (in which the predefined function max, which returns the largest of its arguments, will be useful). Note that the representation of web pages used in this section is a bit odd, since each linked page is nested within the page that links to it (and you can't, therefore, have two pages that link to each other). It's still a useful vehicle for these exercises, which explore some fundamental operations on trees, and the authors refine this representation later in the book.

After that, do exercises 14.4.1 (do the data definition and just two of the parts), 14.4.2 (this goes through a list containing other lists, following the same general pattern as the exercises in the previous section), 14.4.3, and 14.4.4.

Do exercises 15.3.1, 15.3.3, and 15.3.4.

Do exercise 17.6.1 and one exercise chosen from 17.6.2 through 17.6.6. (If you choose 17.6.2, write the reveal-list function, but it's not necessary to do the part of the problem where you use the hangman.ss teachpack to make a complete Hangman game, since that depends on a problem that was not assigned previously.)

Do exercises 17.7.1, 17.7.2 (just parts 1, 3, and 5), 17.7.3, and 17.7.4. Then do exercises 17.8.3 and 17.8.5.

Collect these definitions and submit them as usual via Checkmate.

(c) In class we will discuss how to change our restaurant structure so that instead of just one best dish and its price, each restaurant has a menu of dishes. So a new-rrant is

(make-new-rrant name cuisine phone menu)

where name is a string, cuisine is a string, phone is a string, and menu is a list of dish structures (see below). We'll define the new structure more or less like this:

(define-struct new-rrant (name cuisine phone menu))

The menu is a list of dishes—that is, the new-rrant structure contains a list as one of its fields. Each dish on the list has a name and a price. So a dish is

(make-dish name price)

where name is a string and price is a number, defined with

(define-struct dish (name price))

(c.1) To the restaurant definition below, add a third dish: Paht Woon Sen at $7.95.
(define R1 (make-new-rrant "Thai Touch" "Thai" "949-640-0123"
                           (list (make-dish "Mee Krob" 8.50)
                                 (make-dish "Larb Gai" 10.25))))

Write a Scheme expression that defines R2 as a new-rrant structure for the French restaurant Pascal whose phone number is 940-752-0107; they serve escargots for $12.95, poached salmon for $18.50, rack of lamb for $24.00 and marjolaine cake for $8.50.

(c.2) Write the function new-rrant-first-dish-name that takes a new-rrant as its argument and returns the name of the first dish on the restaurant's menu. Remember to write the test cases and examples before you write the function. You should include code to check whether the menu has zero dishes and return empty if so.

You may find yourself needing to extract the menu from the argument twice; use local to avoid that.

(c.3) Write the function dish-cheap? that takes a dish structure and a number and returns true if (and only if) the price of the dish is less than the specified number.

(c.4) Write the function menu-all-cheap? that takes a menu (i.e., a list of dish structures) and a number and returns true if (and only if) all the dishes on the menu have a price less than the specified number. You may write your code to return true if the menu doesn't have any dishes; don't produce an error message. Of course you should use dish-cheap? in your definition.

(c.5) Write the function new-rrant-all-cheap? that takes a new-rrant and a number and returns true if all the dishes the restaurant serves cost less than the specified number. Of course you should use menu-all-cheap? in your definition.

(c.6) Write the function menu-prices that takes a menu and returns a list of numbers where each number is the price of a dish on the menu. That is, your function will collect all the prices of the dishes into a list and return that list.

(c.7) Write the function menu-average that takes a menu and returns the average price of the dishes on that menu. Think about how you compute an average, what quantities you need, and how to get them. The predefined function length will be helpful; it will also be helpful to write a function sum that returns the sum of a list of numbers. Note also that you'll need to check for an empty menu and return zero in that case, so you don't divide by zero.

(c.8) Write the function new-rrant-cheap? that takes a new-rrant and a number and returns true if the average price of the restaurant's menu is less than the specified number.

(c.9) Write the function new-rrant-keep-cheap that takes a new-rrant and a number and returns (a newly constructed copy of) that restaurant with all the menu items that aren't cheap removed. The right way to go about this is to follow the pattern of the functions above: Start by writing a function to operate on a menu, and then call that function from your new-rrant-keep-cheap function. The actual removal task follows the pattern of some of the functions we've already seen.

(c.10) Write the function cheap-new-rrants that takes a list of new-rrant structures and a number and returns a list containing only the cheap restaurants—the ones whose average menu price is less than the number. Use new-rrant-cheap? in your definition, of course.

Collect all of these definitions and submit them via Checkmate.

(d) Now, reimplement the collection class to store the restaurants in a binary search tree ordered by the restaurants' names. This will involve changing all the definitions in the collection part of the code, but none of the definitions elsewhere.

Your data definition will be as follows:

;; A treenode is either
;; 1. empty
;; 2. (make-treenode rootvalue left right), where rootvalue is a rrant and left
;; and right are treenodes, representing the left subtree and right subtree,
;; and (this is the BST property) where all of the restaurant names in the left
;;
subtree are earlier alphabetically than the name of the rootvalue restaurant,
;; all names in the right subtree are greater, and both subtrees are BSTs.

Here are some tips, hints, and simplifications:

—The code you wrote in part (a) and the code we wrote in class should be a useful guide.

—To compare strings alphabetically, use string=?, string>?, or string<?.

—The collection->list function should do an inorder traversal of the tree, so it produces a sorted list.

—Assume that every restaurant in the collection will have a unique name. Under that assumption, there will be no duplications, so that collection-search will always return a one-element collection or an empty collection.

—Deleting items from a BST is very tricky if the item has two children, because you can't leave holes and you need to maintain the BST property. We'll learn the algorithm for this some day, but for now, you can skip it: collection-remove can just return the same collection unchanged.

(e) Remember that each partner must complete a partner evaluation form on eee.uci.edu.


Based in part on ICS H21assignments and exams by David G. Kay from Fall 2001; modified by David G. Kay, Fall 2004–Fall 2009.


David G. Kay, kay@uci.edu
Friday, October 23, 2009 12:45 PM