The purpose of these practice problems is to simulate the experience of taking Test 2 by providing exemplary problems. On Test 2 you will be given an Eclipse window. You will also be able to view a local copy of the Java API. Internet connectivity will be turned off. Accordingly, you are strongly advised not to look at any resource besides the Java API when taking these practice problems.
(In fact, it's unlikely you'll need the Java API for either these practice problems or the test. I will provide implementations of all abstract data types that you would rely on---lists or queues or whatever. Also, Eclipse itself gives contextual help that provides most of the information you would get from the Java API. Access to the Java API is given only "just in case.")
Note that in the real Test 2 you will not be given a full set of JUnit tests.
Get the starter code from
~tvandrun/Public/cs345/test2-practice
and set it up as you would for a project.
The code is organized into one package per problem
(not in the adt
/impl
etc
packages as in the projects).
Suppose you need an implementation of the Bag ADT for
String
s that supports fast lookup and adding;
"fast" here means logarithmic time.
Further suppose that you know all of the potential keys ahead of time;
that is, when the bag class is instantiated, before you have tallied
any keys, you have a complete list or set of all the String
s
that might be added to the set.
(For example, you are counting word frequencies in a text, but you already
know the full vocabulary in that text.)
Implement the class String
; it is not generic.
Specifically, implement it
so that its operations add()
, count()
,
and remove()
operate in O(lg n) time,
where n is the number of potential keys.
Moreover, assume that the potential keys are passed to the
constructor as an Iterator
that returns the keys
in sorted order.
(Note that the iterator received by the constructor is different from
the iterator returned by the FastBag.iterator()
;
the order of the keys returned by the iterator you write is
unspecified, and it should return the keys the number of times
they occur.)
Test using q1adt.TestFastBag
.
(Hint: The phrases "logarithmic time" and "keys in sorted order" should prompt you to think "binary search.")
Consider the classes q2tree.AVLNode
and
q2tree.RBNode
, which are reduced forms of
the nodes for AVL trees and red-black trees.
Note that, unlike in the project, null links are represented using
the value null
, not instances of a special
"null node" subclass.
Note also that, apart from being able to redden an RBNode
,
the nodes are immutable.
Note further than an AVL node's height and balance are calculated
in the constructor (once for all), but
a red-black node's black height is computed on demand.
Write the method q2tree.AVLToRB.avl2rb()
which takes an
AVL tree represented by its root and produces an
equivalent red-black tree, also represented by its root.
The structure of the two trees should be identical.
The method should be able to handle empty trees (ie, null references).
The resulting red-black tree should have the red-black tree properties
(consistent black height, no two reds in a row) except that the root
may be red.
Recursion is recommended.
Test using q2tree.TestAVLToRB
.
Consider the class q3tree.RBNode
,
which like q2tree.RBNode
is a reduced form
of nodes for red-black trees, but unlike
q2tree.RBNode
does not contain code to compute
the black height (instead it has a public non-final instance variable
blackheight
and cannot be reddened
(the public instance variable isRed
is final).
Write the method q3tree.VerifyLLRB.verifyLLRB()
which takes a red-black tree represented by its root
and does two things: (a) it returns whether or not that tree
satisfies the left-leaning red-black tree property
(consistent black height, no two reds in a row, all reds must be left children)
except that the root is allowed to be red; and
(b) it sets the instance variable blackHeight
in all
the nodes of the tree to the correct value, if the tree satisfies
the properties.
Note that the nodes do not have correctly computed
black heights before the method is called; the method
needs to do (b) for the subtrees in order to do (a) for the root.
Recursion is recommended.
Test using q3tree.TestVerifyLLRB
.
Recall that a cycle
is a closed path in a graph,
that is, a path that begins and ends at the same vertex.
Consider also the interface q4graph.Graph
which is exactly
as it appears in the in-class examples and projects that accompanied
the graph unit.
Write the method q4graph.CheckCycle.checkCycle()
which takes a Graph
(it will be an AdjListGraph
, but
that doesn't matter) and a starting vertex identified by an integer
and determines whether there is a cycle of length at least one
beginning and ending
with that vertex.
(Equivalently, this determines whether or not there is a cycle
that includes this vertex, since it doesn't matter which vertex in the
cycle is its beginning or ending point.)
(One could argue that all vertices are in a cycle, a trivial cycle of length zero. We don't count that. We're looking for cycles that have at least one edge. Note that, however, a vertex with a self loop has a cycle of length one.)
If it helps you think about it, you may assume that the graph is directed.
(Hint: There are two graph algorithms that each could be adapted to this problem.)
Test using q4graph.TestCheckCycle
.
The transpose of a graph is a graph with the same (number of vertices) but with the edges reversed. That is, for graph G = (V, E), the transpose of G is GT = (V, ET) where edge (u, v) is in ET if and only if (v, u) is in E.
Consider the class q5graph.AdjListGraph
which
is exactly as it appeared in the in-class examples and projects from
the graph unit.
Note in particular the nested class ALGBuilder
which
is used to build a new AdjListGraph
.
Specifically, to build a new graph, use this pattern:
// make the builder AdjListGraph.ALGBuilder builder = new AdjListGraph.ALGBuilder(); // ... add edges using builder.connect(u, v) ... // now that we're done, get the graph AdjListGraph g = builder.getGraph();
Write the method q5graph.ComputeTranspose.computeTranspose()
,
which takes a AdjListGraph
and produces another
AdjListGraph
that is the transpose of the
one given.
Test using q5graph.TestComputeTranspose
.