CS 330 Home Schedule Resources

Homework 8
More Algorithms On Lists.

Estimated time: 4 hours

Acceptance tests for assignment 8.

Grading rubric (i.e. point values) for problems.

Objectives: Practice declarative techniques on lists and trees, and higher-order programming.

This assignment delves further into concepts related to declarative programming on lists. It focuses on the implementation of more complicated algorithms than those of Assignment 3. For all problems where you are directed to write or define a procedure, submit your code with your homework.

Exercises

  1. I sort, you sort, we all sort... This exercise consists in implementing algorithms in the declarative model . Implement and test ONE of the two sorting algoritms below. Whichever you choose, call the function Sort. Make your implementation as efficient as possible, using tail recursion and difference lists if reasonable. Each algorithm is illustrated with the list [5 1 7 2 6 4 3 ].

  2. Consider a list of two type of elements: atoms and integers.
    Define such a structure in EBNF notation.
    Write a function SumInts which calculates the sum of all the integers in the list (ignoring the atoms).
    Hint: Use pattern matching and the built-in IsInt function, and deduce the various required cases from the EBNF.


  3. Three steps forward, two steps back...
    This exercise is intended as an example using accumulators as a means of programming with state in the declarative model.
    A stack is an ADT (Abstract Data Type) proposing the following accesses to the data:
    In our exercise, the state contains two components: the stack itself, represented by a list, and the number of elements in the stack. The state is thus a tuple (L,N).

    Write the procedures
    {Push X Lin ?Lout Nin ?Nout}
    {Pop ?X Lin ?Lout Nin ?Nout} and
    {IsEmpty ?X Lin ?Lout Nin ?Nout}.

    (? means that the variable which follows is affected by the procedure; it is thus a result of the procedure.)

    Now that we have defined our abstract type, stack, we will be able to use it as in this illustrative example:

    Define a procedure { Twosteps Lin ?Lout Nin ?Nout } which models with a stack the fact that somebody advances according to the song "Three steps forward, two steps back...".
    The modeling of a step is done by introducing the element forward on the stack. For a step back, one withdraws one forward.
    Twosteps will thus contain instructions of the type
    {Push forward Lin Lout Nin Nout}
    and the state will thus move (L,N) successively through these states:

    (nil, 0)
    ([ forward], 1)
    ([ forward forward], 2)
    ([ forward forward forward], 3)
    ([ forward forward], 2)
    ([ forward], 1)

    Check this final state.

    One can deduce from it that at the end of a stage "three steps forward, two steps back", that one advanced overall 1 step ahead!

  4. Trees.
    A general binary tree is either an element by itself (a leaf containing a value but no children), or a tuple with a value and two sub-trees (called children).

    Formalize this intuitive definition in EBNF notation. Write the EBNF.
    Suppose then that the values of the nodes are integers. Build a small tree and assign it to a variable called Tree. Show your code.

    [Don't write a tree-building function, just assign it to a variable from a literal. If trees were composed of foos and bars, for instance, this would be Tree = foo(bar(bar)). In other words, show how to translate the EBNF into Oz code. -Max]

    Note: You can use the Drawer module to visualize the constructed tree.

    Write a function {Sum T} which returns the sum of the values of all the nodes of the tree. Use pattern matching and deduce the various cases from the definition which you formalized. For full credit, make sure your function is tail-recursive.

  5. Depth-first search. A traversal of a tree is known as depth-first if, starting from the tree's top (root), one first visits all the descendants of a node before visiting its neighbors. Write a function {DepthFirst T} which takes a tree as a parameter and returns a list of the values of the nodes visited in depth-first order.

    Hint: This problem can be solved similarly to Flatten covered in class and in the textbook at the bottom of page 144 by building the output list from tail to head.

  6. Cube roots. Do Exercise 2 on page 230 of textbook. Implement two versions: one in the style of Figure 3.5 (p. 121) and the other in the style of Figure 3.8 (p. 123). Call them Cube1 and Cube2, respectively. Compare their efficiency by running each with the same set of 100 different inputs and averaging their runtimes. (You can use the built-in Property.get function to get the current time in milliseconds, e.g.: CurrentTime = {Property.get 'time.total'}'.) Also, verify whether they behave the same in terms of visiblity of the helper routines.

  7. Feedback.
    Scale
    1. Not at all
    2. Not very
    3. Slightly
    4. Somewhat
    5. Mostly
    6. Very
    7. Extremely

Notes