Supplementary Exercises:
When too much DAT is barely enough!
Below are some supplementary problems, in some cases more challenging,
that build on the material covered in the unit. (They are not
directly examinable as such, but provide some extra practice.)
Recursive Performance Analysis
- In Exercise Sheet 5 you implemented a data structure
StackCharLinked for holding a stack of
chars. Modify this to provide a more general stack
StackLinked of Objects.
- In a new class called
HoldsWhat, write a
recursive class method:
- isStackOfStrings(Object ob): returns true if
Object ob is a StackLinked of
Strings, and false otherwise.
Thus the method should return false if it is passed a null
reference, an object other than a StackLinked, or if the stack
holds anything other than Strings. (You are not expected
to optimise the code.)
Hint: Look at the code for
Pair.equals() in the DAT Notes for inspiration.
Write a small test program to ensure that your method works
as expected.
- Perform an asymptotic time analysis of your
isStackOfStrings method. Note any assumptions you
make. You should find a recurrence relation and a closed form
expression for the time taken with respect to stack size. What
is the time complexity (smallest `big O') of the method?
Trees
For some more practice at trees and recursion, try the following:
- Write a method toString (and any supporting methods
needed) that returns a string representation of your tree, where
each subtree is indented by two more spaces than its parent.
Thus the tree:
a
/ \
q r
/ \ / \
w e null null
/ \ / \
null null null null
would be printed out as:
a
q // a's first subtree starts here
w // q's first subtree
e // q's second subtree
r // a's second subtree starts here
As usual test your method by creating some trees and
printing them out.
Note that this is the easiest way to print a tree, as it
corresponds to a depth-first traversal. The easiest way of
implementing toString is of course, therefore,
recursively.
Hint: Delegate the printing of each TreeCell to the
TreeCell itself!
If you are having trouble with this, start by printing a
non-indented version, so the above tree would print:
a
q
w
e
r
Once you have done this try adding the indentation.
- A Royal Tree can be built by associating, with each person in a
royal family, their next eldest sibling (if any), and
their eldest offspring (if any). For example, the following diagram
shows part of the Royal Tree for a typical royal clan:
liz -> null
|
v
chuck -> anne -> andy -> eddie -> null
| | | |
| v v v
| null null null
v
bill -> hank -> null
| |
v v
null null
Store this or your own family tree using your BinTree ADT and modify
your toString method so that it prints the tree out in the
following form:
--> liz
--> none
--> chuck
--> anne
--> andy
--> eddie
--> none
--> none
--> none
--> none
--> bill
--> henry
--> none
--> none
--> none
-
*Challenge*
Finally, modify your toString method(s) so that it prints out
trees in the following, more elegant and readable, form:
--> liz
|
+--> none
|
+--> chuck
|
+--> anne
| |
| +--> andy
| | |
| | +--> eddie
| | | |
| | | +--> none
| | | |
| | | +--> none
| | |
| | +--> none
| |
| +--> none
|
+--> bill
|
+--> henry
| |
| +--> none
| |
| +--> none
|
+--> none
Binary Search
- Write code for a method needed(n) which returns the
maximum number of calls to
bSearch (from the DAT
Notes section on Maps) needed to search for an
item in a block of
size n.
- We have shown in the Maps section of the Notes that the number of
calls to bsearch for a list of size n is given by
Tn = log2 n + 1 for cases where n
is a power of 2. For cases where n is not a power of 2,
Tn is greater than log2 n
+1. For example, T7 = T8 =
log2 8 + 1 = 4. However log27 <
log28, so T7 > log2 7 +
1. Show that, despite this, Tn is
O(log2 n).
Hint: Compare Tn with log2 n +
2. To deal with the `2' you might use the fact that 1 <
log2 n for n > 2.
Arrays
- Part of an implementation for a 2-dimensional Array
using a lexicographic ordering was covered in an
exercise in Section 11 of the DAT Notes. Complete this
implementation.
- Re-implement your Array ADT using a shell-ordered
addressing function.
- Change your constructors so that they reserve blocks
which are four times the size required to accommodate
the array dimensions. (This is rather artificial - the
idea is to simulate the availability of a larger block
of memory.)
Now add to each of your arrays a method extend(m,n) that
increases the number of rows in the array to m
and the number of columns to n and throws an
exception if the change cannot be accommodated. (Your method
must of course relocate any items as necessary. Your
test program should check that the items can be accessed
at the correct addresses in the resulting array.)
Hash Tables
The following table lists the albums in my record collection:
| Artist/Group
|
Album Title
|
Record Label
|
| Boz Scaggs
|
Silk Degrees
|
Sony
|
| Sweet Blue Midnights
|
This Year's Kisses
|
A little Perth label
|
| Mamas and the Papas
|
California Dreamin'
|
MCA
|
| Tom Waits
|
The Heart of Saturday Night
|
WEA
|
Store this information in a Hashtable (from
java.util) with an initial size of 4 and a load factor of
0.5, using the Artist/Group as a key. Add some of your own records. Then
retrive all the records and print them out in a list.
Hint: Java's Hashtable stores keys along with objects
containing the "record" of information. (There are of course no
records in Java as there are in Pascal. There is no need for them -
objects are far more versatile.) Create a class Record to
bundle up the information to be stored alongside the key.
|