CSC 151-02, Fall 2006 : Schedule : Lab 39
Summary: In this lab, you will investigate some aspects of our implementation of the Queue ADT. You will also compare how an algorithm differs depending on whether it uses queues or stacks.
Contents:
Create a new file that contains the implementation of stacks from the reading on stacks and the implementation of queues from the reading on queues.
Consider the following set of operations:
a. What do you expect to happen if the add
is treated as a stack-based push and the get
as a stack-based pop?
For example,
> (define s (make-stack))
> (s ':push! "Aardvark")
> (s ':push! "Baboon")
> (s ':push! "Civet")
> (s ':pop!)
...
b. Check your answer experimentally.
c. What do you expect to happen if the add
is treated as a queue-based enqueue and the get
as a queue-based dequeue?
For example,
> (define q (make-queue))
> (q ':enqueue! "Aardvark")
> (q ':enqueue! "Baboon")
> (q ':enqueue! "Civet")
> (q ':dequeue!)
...
d. Check your answer experimentally.
While we want to limit information about the implementation to client programmers, it is often convenient when designing or debugging an object to add (temporary) methods that let us look more closely at that implementation.
a. Add a dump message to the queue implementation. When the
queue receives this message, it should display both lists in whatever
way you find most useful. For example
> (myqueue ':dump)
Front: (b c)
Back: (f e d)
b. Redo the enqueue and dequeue operations given in the previous exercise, observing the state of the queue after each step.
c. What, if anything, do your results tell you about our implementation?
As you may recall, a symbol tree is either (1) a symbol or (2) a pair of two symbol trees. Here's one technique for printing all the symbols in a tree, based on the concept fo deep recursion:
(define print-symbols
(lambda (tree)
(if (pair? tree)
(begin
(print-symbols (car tree))
(print-symbols (cdr tree)))
(begin
(display tree)
(newline)))))
a. What do you expect the output to be for the following tree?
(define animals
(cons
(cons
(cons "Aardvark" "Baboon")
"Chimp")
(cons
"Dingo"
(cons
(cons "Emu" "Frog")
(cons "Gnu" "Hippo")))))
b. Confirm your results experimentally.
c. It is also possible to write a flat-recursive procedure to print the tree by storing the subtrees to print in a queue. At each step, you get something from the queue. If it's a pair, you enqueue both subtrees. Otherwise, you print it out. You stop when the queue is empty. Here's a skeleton for such a procedure:
(define new-print-symbols
(let ((queue (make-queue)))
(letrec ((kernel
(lambda ()
(if (queue ':empty?)
(newline)
(let ((subtree (queue ':dequeue!)))
(if (pair? subtree)
(begin
...)
(begin
...))
(kernel))))))
(lambda (tree)
(queue ':enqueue! tree)
(kernel)))))
Finish implementing this procedure, enqueueing the left subtree before the right.
d. What do you expect the output to be given the tree above?
e. Check your results experimentally.
f. What do you expect to happen if you enqueue the right subtree before the left?
g. Check your results experimentally.
a. Instead of using a queue for the procedure in the previous exercise, you could use a stack. Create a variant of that procedure that uses stacks instead of queues and that pushes the left subtree before the right.
b. What do you expect the output of your procedure to be given the tree above?
c. Check your results experimentally.
d. What do you expect the output to be if you push the right subtree before the left?
e. Check your results experimentally.
f. Of the four implementations, which is most like the original, deep recursive procedure?
Janet Davis (davisjan@cs.grinnell.edu)
Created November 26, 2006 based on