Q1: 10 points Q2: 15 points Q3: 15 points Q4: 15 points Q5: 15 points Q6: 10 points Q7: 20 points Total: 100 points
Here is a code base from previous assignments, that is assumed to be available throughout the exam:
public class Dog {
private String name;
private int age;
// public get and set methods, two-parameter constructor
}
public class SledDog extends Dog {
private String breed = "Husky";
// public get and set methods, three-parameter constructor
}
public class LinearNode<T> {
private T element;
private LinearNode<T> next;
// public get and set methods, zero-parameter and one-parameter constructors
}
public class DogTeam {
private LinearNode<SledDog> leadNode;
private int size;
// public get and set methods, zero-parameter constructor
public void addToLead (SledDog newLead) {…}
public SledDog removeLead ( ) {…}
public void switchLastTwo ( ) {…}
public SledDog removeYoungest ( ) {…}
public int countHuskies ( ) {…}
}
Code run before other code fragments:
Dog ace = new Dog ("Ace", 6);
Dog biscuit = new Dog ("Biscuit", 1);
Dog cardie = new Dog ("Cardie", 3);
Dog duncan = new Dog ("Duncan", 1);
SledDog balto = new SledDog ("Balto", 92, "Husky");
SledDog king = new SledDog ("King", 73, "Husky");
SledDog buck = newSledDog ("Buck", 108, "Mixed");
Some useful API information for L&C's code base:
public interface ListADT<T> extends Iterable<T> {
public T removeFirst( );
public T removeLast( );
public T remove (T element);
public T first( );
public T last( );
public boolean contains (T target);
public boolean isEmpty( );
public int size( );
public Iterator<T> iterator( );
public String toString( );}
public interface OrderedListADT<T> extends ListADT<T> {
public void add (T element);}
public interface UnorderedListADT<T> {
public void addToFront (T element);
public void addToRear (T element);
public void addAfter (T element, T target);}
// Note: For this exam is is assumed that the class ArrayList implements UnorderedListADT
public class SortingandSearching {
public static <T extends Comparable<? super T >> boolean
linearSearch (T [ ] data, int min, int max, T target) {...}
public static <T extends Comparable<? super T >> boolean
binarySearch (T [ ] data, int min, int max, T target) {...}
public static <T extends Comparable<? super T >> void
selectionSort (T [ ] data) {...}
public static <T extends Comparable<? super T >> void
quickSort (T [ ] data, int min, int max) {...}
public static <T extends Comparable<? super T >> void
mergeSort (T [ ] data, int min, int max) {...}}
Selection sort repeatedly finds the smallest element in the list, removes it, and places it at the tail of a new list. Insertion sort repeatedly takes a new element and inserts it into an ordered list, so that the new list remains sorted. Both take O(n2) time on array-based structures.
add
(in an ordered list) and
addAfter
(in an unordered list)
The one-parameter add
method places the new element in
its appropriate place in the calling ordered list. The
two-parameter addAfter
method places the new element
immediately after the target element in the calling unordered list,
and throws an exception if the target element is not already there.
Cloneable
and Serializable
Both are interfaces extended by the List
interface in
java.util
-- Cloneable
is a signal to the
runtime system that the clone
method of the
Object
class, which creates a deep copy of the calling
object, is supported. (If you said that a
Cloneable
had to have the clone
method I
gave full credit.) Hardly anyone remembered
Serializable
, which is an indication that objects of
the calling type may be written to and read from files.
ArrayList
(in L&C) and java.util.ArrayList
Both are array-based implementations of lists that resize their arrays
as necessary to deal with inserted elements. But the
java.util
class is an indexed list -- it has
methods to access elements based on their current position in the
array, such as get(i)
and set(i)
. They
also have different names for many methods -- in general, the
java.util
class has far more methods.
Iterable
and Iterator
Both are interfaces dealing with iterators, auxiliary objects that
give all the elements of a collection when repeatedly asked. Iterator
classes normally implement the Iterator interface, which requires the
methods hasNext
, next
, and
remove
, though this last method is often not supported.
The Iterable
interface is normally implemented by the
class that has the iterator -- it requires the method
iterator
which returns an iterator object attached to the
calling collection.
SledDog
objects occurred. Describe (in English) what code I should add to
what methods and classes.
The most natural thing would be to add a static int field to either
the
SledDog
or DogTeam
classes, that would be
initialized at 0 and incremented by the compareTo
method of SledDog
whenever it was called. We would
need methods to retrieve and to reset this counter. It would be
possible to have an instance field on each SledDog
or
on each DogTeam
counting how many comparisons it had
been involved in. To get the total from this we would have to add
the numbers for every dog or for every team, dividing by two if the
comparison is counted for both its arguments.
There are various ways to do the calculation of the spoons brought into the town, based on the number of spoons at the preceding place. All of these have a parameter 0.05 for the tax rate in the Project #5 solution, and we simply change that parameter to 0.10 to get the new tax rate.
moveOneDisk
method modify these data structures?
The disks are added to and removed from a pin at only one end, so the
simplest idea would be to keep the disk objects on three stacks.
The moveOneDisk
method would pop a disk from one stack
and push it onto another. Either in that method or elsewhere, there
would have to be a check that the disk pushed was smaller than the
top disk on that stack, if any.
UnorderedListADT<Dog> pack = new ArrayList<Dog>( );
pack.addToFront (duncan);
pack.addAfter (cardie, duncan);
pack.addToRear (biscuit);
Dog x = pack.remove (duncan);
Dog y = pack.removeLast( );
pack.addToFront (x);
pack.addAfter (y, cardie);
System.out.println (pack.last( ).getName( );
The list goes from empty to (D) to (D, C) to (D, C, B) to (C, B) (x set to D) to (C) (y set to B) to (D, C) to (D, C, B). The return value is B so the string printed is "Biscuit".
public static int fred (int n) {
if (n == 0) return 1;
else return ginger (n) + fred (n-1);}
public static int ginger (int n) {
if (n == 0) return 0;
else return ginger (n-1) + fred (n-1);}
System.out.println (fred(3));
As with Fibonacci numbers, the best way to compute the values of F(i) and G(i) is bottom up: G(0) = 0, F(0) = 1, G(1) = 0 + 1 = 1, F(1) = 1 + 1 = 2, G(2) = 1 + 2 = 3, F(2) = 2 + 3 = 5, G(3) = 3 + 5 = 8, and finally F(3) = 5 + 8 = 13. Clearly these functions are a lot like the Fibonacci numbers.
public static int netCaps (String input) {
if (input.equals ("")) return 0;
char first = input.charAt(0); // first letter
String rest = input.substring(1); // all but first letter
if ('A' <= first && first <= 'Z') return netCaps (rest) + 1;
return netCaps (rest) - 1;}
System.out.println (netCaps ("i Can HaZ chEEzburGer?");
The function recurses repeatedly on all but the first letter of the string, until it reaches the base case of the empty string. As it finishes each substring, it adds one for every capital letter and subtracts one for every character that is not a capital letter. Since the given string has six capitals and sixteen non-capitals (counting the spaces and the question mark), the output is -10.
public int abbott (int n) {
if (n == 0) return n;
else return abbott (n-1) + costello (n);}
public int costello (int n) {
if (n == 0) return 1;
else return abbott (n) + costello (n-1);}
System.out.println (abbott (2) + costello (3));
This is an example of an ungrounded indirect recursion. The computation begins by trying to evaluate A(2), which is A(1) + C(2), which is A(0) + C(1) + C(2), which is C(1) + C(2), which is A(1) + C(0) + C(2), and so forth -- the call to A(1) produces a call to C(1) which produces another call to A(1), which will call C(1), so that the calls never reach a base case. The computation will not terminate normally but will have a runtime error when the method stack overflows.
// uses L&C code base, usual dogs are defined as above
ArrayList<Dog< kennel = new ArrayList<Dog>( );
kennel.addToFront (cardie);
DogTeam redSox = new DogTeam( );
redSox.addToLead (balto);
kennel.addAfter (king, cardie);
kennel.removeFirst ( );
redSox.addToLead (kennel.removeFirst( ));
if (kennel.isEmpty( )) System.out.println ("No more dogs");
else System.out.println (kennel.first( ).getName( ));
This is the same error that was on the second midterm -- in line 7,
the object returned by the method call kennel.removeFirst(
)
has type Dog
, although the actual object in
the run of this code fragment
happens to be king
who is a SledDog
. The
compiler will not let the output of this call be the argument of the
call redSox.addToLead( )
, which must be a
SledDog
, because it cannot guarantee that it is of that type.
public class Group<T extends Comparable<T>> {
private T[ ] members;
private int size;
public Group (int capacity) {
members = new T[capacity];
size = 0;}
public T getMember (int i) {return members[i];}
public void setMember (int i, T newElem) {
if (members[i] == null && newElem != null) size++;
if (members[i] != null && newElem == null) size--;
members[i] = newElem;}
// more methods
public int compareTo (Group other) {
if (this.size < other.size) return -1;
if (this.size == other.size) return 0;
return 1;}}
In line 5, this code attempts to create an array of a generic type,
which is not allowed -- we must create an array of objects and cast it
into the type This class has a T[ ]
. This will not compile.
compareTo
method without implementing
the Comparable
interface -- this is unusual but not an
error. The base type T
of this collection class is
restricted to be an ordered type, but the comparison operator on the
collections does not use this.
public static int twotoThe (int n) {
if (n <= 0) return 1;
return twoToThe (n-1) + twoToThe (n-1);}
The original call with parameter n leads to two separate calls with parameter n-1, then four calls with parameter n-2, eight with parameter n-3, and so on to have 2i calls with parameter n-i for each number i until i = n, when we have 2n calls to the base case with parameter 0. Each of these calls takes O(1) time and the total number of them is 2n + 2n-1 + ... + 1 = 2n+1 - 1. Thus the total time is O(2n).
public static int foo (int n) {
int x = 0; y = n;
for (int i = 0; i < n; i++) {
y = y/2;
if (y <= 1) break;
for (int j = 0; j < n; j++)
x += (y * i + j);}
return x;}
This looks like two nested loops each executing n times, with an O(1) body, which would be O(n2) time. But the outer loop only executes log n times, because the variable y is halved each time through and the loop is broken when y reaches 1. We have O(log n) times through the outer loop, each involving O(n) times through the inner loop, for a total time of O(n log n).
// uses L&C's binarySearch method, goes in L&C's SortingAndSearching class
// "n" is the combined length of the two input arrays
public static <T extends Comparable <? super T>> boolean
sameElements (T [ ] one, T [ ] two) {
boolean soFar = true;
for (int i = 0; i < one.length; i++)
if (!binarySearch (two, 0, two.length - 1; one[i]))
soFar = false;
for (int j = 0; j < two.length; j++)
if (!binarySearch (one, 0, one.length - 1; two[j]))
soFar = false;
return soFar;}
Each of the loops executes n times, and the times of the two loops add
because they are not nested. Within each loop is a call to
binarySearch
on an interval of length n, which takes
O(log n) time. So the total time is O(n log n).
In Lecture #25 we mentioned Counting Sort, another algoirthm to sort an array that takes O(n2) time. The idea is that if the n elements of the array are distinct, we can compare each element x to the other n - 1 elements in the array, and thus determine exactly how many elements in the array are less than x.
Write a generic method
public static <T extends Comparable<? super T>> T
[ ] countingSort (T [ ] input)
that returns an array that is a sorted copy of the array input.
Your method should not change the input array at all. The declaration
in angle brackets allows you to assume that T
has a
compareTo
that we use to define the proper order on its elements.
I deducted two points for forgetting the cast operation in creating
the generic array. Many people tested the output of
public static <T extends Comparable <? super T>> T[ ]
countingSort (T[ ] input) {
T[ ] output = (T[ ]) new Object[input.length]; // cast is required
for (int i = 0; i < input.length; i++) {
int lesser = 0;
for (int j = 0; j < input.length; j++)
if (input[j].compareTo (input[i]) < 0) lesser++;
output[lesser] = input[i];}
return output;}
compareTo
for equality with 1 rather than being greater
than 0 (or similarly for -1 and less than 0). While all the
compareTo
methods we have seen or built have output -1,
0, or 1, the spec for the method only says that the output must be
less than, equal to, or greater than 0 according to the relation of
the elements. I did not deduct any points for this error.
A subteam of a DogTeam
object x is a
DogTeam
that contains a subset of the dogs in x, in the
same order as they occur in x. For example, if x contains dogs a, b,
and c, there are eight subteams of x: the empty team (written [ ]),
[a], [b], [c], [a, b], [a, c], [b, c], and [a, b, c].
The following is a recursive definition of the set of subteams of x. If x has no dogs in it, there is exactly one subteam which also has no dogs in it. Otherwise, let d be the lead dog of x and let y be the team made from x by removing d. Then the subteams of x consist of the subteams of y, plus every team that is made from a subteam of y by adding the dog d to it at the lead.
Write a recursive method public DogTeam[ ] listSubteams(
)
to be included in the DogTeam
class. If this
method is called by a DogTeam
object with k dogs in it,
it should return an array consisting of all the 2k possible
subteams of x. You are not required to list the subteams in any
particular order, but ther is an order that is most natural for the
recursive definition. Assume that you have a static method
int twoToThe (int k)
that will return the number 2k
when given input k.
Make sure that your method has no side effects on the calling
DogTeam
object.
If you find it convenient, you may assume that you have the
iterator
method from Project #6, and the corresponding
iterator class, available to use in your code.
public DogTeam[ ] listSubteams ( ) {
DogTeam [ ] output = new DogTeam (twoToThe(size)); // no cast, not generic
if (isEmpty( )) {
output[0] = new DogTeam( ); // we return array of one empty team
return output;}
DogTeam temp = clone( ); // clone method using given methods is below
SledDog lead = temp.removeLead( );
DogTeam[ ] half = temp.listSubTeams( ); // array of 2^{size - 1} teams
for (int i = 0; i < half.length; i++) {
output[i] = half[i];
half[i].addToLead(lead);
output[i + half.length] = half[i];}
return output;}
public DogTeam clone( ) { // uses iterator from Project #6
DogTeam ret = new DogTeam( );
DogTeam temp = new DogTeam( );
for (dog : this) temp = addToLead (dog); // temp is this backwards
for (dog : temp) ret.addToLead (dog); // ret is now clone of this
return ret;}
Last modified 19 November 2011