# Solutions to Practice Final Exam

### Directions:

• Answer the problems on the exam pages.
• There are seven problems for 120 total points. Likely scale is A=105, C=70.
• If you need extra space use the back of a page.
• No books, notes, calculators, or collaboration.

```  Q1: 20 points
Q2: 15 points
Q3: 15 points
Q4: 15 points
Q5: 15 points
Q6: 20 points
Q7: 20 points
Total: 120 points
```

Question text is in black, solutions in blue.

Format is similar to the midterms, some text explaining the question types is omitted.

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 int size;
// public get and set methods, zero-parameter constructor
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 void push (T element);
public T pop ( );
public t peek ( );
public boolean isEmpty( );
public int size ( );
public String toString( );
public void enqueue (T element);
public T dequeue ( );
public T first ( );
public boolean isEmpty( );
public int size ( );
public String toString ( );
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 void addAfter (T element, T target);}
public class SortingandSearching <T> {
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) {...}}
public T getRoot ( );
public boolean isEmpty( );
public int size( );
public boolean contains (T target);
public T find (T target);
public String toString( );
public Iterator<T> iteratorPreOrder( );
public Iterator<T> iteratorPostOrder( );
public Iterator<T> iteratorInOrder( );
public Iterator<T> iteratorLevelOrder( );}
public interface SetADT<T> extends Iterable<T> {
public T removeRandom ( );
public T remove (T element);
public boolean contains (T target);
public boolean isEmpty ( );
public int size ( );
public Iterator<T> iterator( );
public String toString ( );}

``````

• Question 1: Java Concepts Briefly explain the difference between the two concepts in each pair (2 points each).

• a) O(1) time and O(n) time

A piece of code runs in O(1) time if there is a constant c such that the code never takes more than c time on input of any size. It takes O(n) time if there is a c such that it never takes more than cn time on any input of size n (when n is sufficiently large).

• b) `public class Foo` and ```public class Foo extends Object```

There is no difference between the two as every class automatically extends `Object`.

• c) is-a Stack and has-a Stack

An object is-a Stack if it extends the Stack class (or in L&C's terms, implements the `StackADT` interface). It has-a stack if it has an instance field of type Stack (or `StackADT`).

Both are linear structures made of nodes. In a singly linked structure each node except the last has a pointer to the following node. In a doubly linked structure each node except the first also has a pointer to the node before it.

• e) merge sort and quick sort

Both are recursive O(n log n) time sorting algorithms. Merge sort divides the set to be sorted in half arbitrarily, sorts each half recursively, and merges the two sorted halves. Quick sort picks a pivot element, divides the set into those elements less than the pivot and those greater than it, sorts each piece recursively, and places the sorted pieces in the correct place.

• f) grounded recursion and ungrounded recursion

A recursion is grounded if any legitimate input will cause it to terminate, since every seqeunce of calls will eventually reach a base case. It is ungrounded if some legitimate input causes an infinite sequence of recursive calls, so that the process never terminates.

• g) ordered list and unordered list

Both are linear structures, but an ordered list is kept so that the elements are in order according to some given comparison operation. When an element is added to an ordered list, there is normally only one place in the sequence it may go to preserve the order. An element added to an unordered list may legally go anywhere.

• h) `java.util.List` and `java.util.LinkedList`

`List` in `java.util` is an interface giving all the methods for an indexed list. `LinkedList` is a class implementing that interface, built as a linked structure.

• i) heap and binary search tree

Both are tree structures. A heap is partially ordered in that each parent element is smaller than its children (in a min-heap), and a heap of a given size has a fixed structure, almost balanced with all leaves left-justified on the last level. A binary search tree has the property that for every node x, all elements in the node's left subtree are less than x and all nodes in its right subtree are greater than x. There is no requirement that it have any particular structure.

• j) inorder traversal and level-order traversal

The inorder traversal traverses all nodes in the left subtree of x before it traverses x, and all elements in the right subtree after it traverses x. The level-order traversal begins with the root, then all nodes at depth 1, then all at depth 2, and so forth until it traverses the nodes of maximum depth.

• Question 2: Software Engineering -- 5 points each

• a) In Project #7, how would you modify the code so that a PrefixTree could report the number of nodes it has at each level?

I would create an `int` array `numberAtLevel` of size 6, so that `numberAtLevel (i)` will record the number of nodes at level 1. I would initialize this array to all 0's, then traverse the tree in one of our four standard ways, incrementing the appropriate counter for each node. How does a node know what depth it is at? In our implementation the string stored in a node of level i was always at depth i.

• b) How would you modify a hash table, with chaining, so that it would rehash to a new size whenever any of its buckets got more than five items?

If my chains are stored as `ArrayList` objects, for example, each chain knows how many elements it has. Whenever I add an element, I check whether the add makes a chain that is too big, and trigger a resize operation if it does.

• c) In Project #2, #4, or #5, how would you add a method `directions` that would take a source and destination cell and return a string describing a sequence of north, east, south, and west moves that would take you from the source to the destination, using only open cells? (It should return the string "no path" if there is no path.)

The output of our `path` method in each case was an array of cells if the path existed, and an empty array if not. So my `directions` method just needs to call `path`. If the output has length 0, I report "no path". Otherwise I go through the output, determine which length-1 move was needed to go from each cell in the array to the next, and write a description of that move to my output.

• Question 3: Tracing Code -- indicate the output of each code fragment (5 points each)

• a)
``````
// uses L&C code base, Dog class, standard dogs from above
Set<Dog> kennel = new ArraySet<Dog>( );
boolean b = kennel.contains (duncan);
boolean c = kennel.contains (biscuit);
if (b || c) kennel.remove (cardie);
Dog z = kennel.removeRandom ( );
System.out.println (z.getName( ));
``````

Cardie goes in, and Duncan goes in on top of her. We set b to true and c to false. Since `b || c` is true, we remove Cardie. We add Duncan, which has no effect since he is already in. The random Dog removed must be Duncan since he is the only dog in the set. So we print "Duncan".

• b)
``````
Dog terrier = duncan;
Dog retriever = cardie;
terrier.setName (cardie.getName( ));
retriever.setName (duncan.getName( ));
if (terrier == cardie) duncan.setName ("Biscuit");
System.out.println(cardie.getName( ) + " " + duncan.getName( ));
``````

There are only two dogs involved here, though each has multiple names. We set the name of the dog originally named "Duncan" to "Cardie". The second setName thus has no effect, as it sets Cardie's name to "Cardie" which it is already. But there are still two different dogs, and `terrier` is one and `cardie` the other. So the third setName operation does not happen and we print "Cardie Cardie".

• c) We are given a heap of ints implemented as an array of ints with the children of each entry i being entries 2i + 1 and 2i + 2. We add the ints 3, 7, 4, 23, 19, 2, and 9 into the heap in order. We then do three `removeMin` operations. What are the resulting contents of the array? (Assume that the initial capacity was 10.)

``````
empty
3
3   7
3   7   4
3   7   4  23
3   7   4  23  19
2   7   3  23  19   4
2   7   3  23  19   4   9
3   7   4  23  19   9
4   7   9  23  19
7  19   9  23
``````

• Question 4: Finding Errors -- indicate whether the code fails to compile, throws an exception on reasonable input, or has clearly unintended output (5 points each):

• a)
``````
// method to be added to the DogTeam class
public SledDog [ ] toArray ( ) {
SledDog [ ] ret = new SledDog [size];
if (size == 0) return ret;
int index = 0;
while (cur.getNext( ) != null) {
index++;
ret[index] = cur.getElement( );
cur = cur.getNext( );}
return ret;}

``````

The method is correct for size 0 and 1, but if the while loop actually operates we get a clearly unintended output. The lead node's element is placed into `ret[1]` as well as `ret[0]`, and the subsequent elements are placed one entry further down than they belong. The last element in the list is never placed into the array.

• b)
``````
// method to be added to the DogTeam class
public DogTeam clone( ) {
DogTeam ret = new DogTeam( );
if (size == 0) return ret;
size--;
new LinearNode<SledDog>(cur);
ret = this.clone( );
return ret;}

``````

This won't compile because the variable `cur` is a node, but the one-parameter constructor for `LinearNode<SledDog>` expects a `SledDog`. Otherwise the logic works.

• c)
``````
// method to be added to the Maze class of projects 1 and 2
public int countOpenCells ( ) {
count = 0;
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
if (cells[i, j].isOpen( )) count++;
return count;}

``````

This won't compile because the variable `count` is never declared.

• Question 5: Timing Analysis (in terms of n, we use L&C's code base) -- 5 points each

• a)
``````
// method to be added to DogTeam class
public void rotate ( ) {
if (size <= 1) return;
rotate ( );
old.setNext (second);}
``````

This method rotates a team of size n by removing the lead element, rotating the remaining team, and replacing the old lead elmement in the second position. So rotating a team of size n means rotating a team of size n-1, which means rotating a team of size n-2, and so on until we reach a team of size 1, which is rotated by doing nothing. There are O(n) recursive calls, and each one involves only O(1) work, so the total running time is O(n).

• b)
``````
// method to be added to DogTeam class
public void reverse ( ) {
if (size <= 1) return;
if (size == 2) {
return;}
reverse( );
reverse( );
``````

Here reversing a team of size n means reversing two teams of size n-1, which means reversing four teams of size n-2, eight teams of size n-3, and so on. We eventually reach the base case but we have O(2n) calls to it for O(2n) total time.

• c)
``````
// uses L&C code base; n is size of input queue
public static void reorder (QueueADT<Dog> q) {
int n = q.size( );
if (n <= 6) return;
Dog d = q.first( );
for (int i = 0; i < 3; i++)
temp.enqueue (q.dequeue( ));
for (int j = 0; j < 3; j++)
q.enqueue (q.dequeue( ));
while (!temp.isEmpty( ))
q.enqueue (temp.dequeue( ));
while (d != q.first( ))
q.enqueue (q.dequeue( ));}

``````

On a queue of length greater than 6, we move the first three elements onto `temp`, move the next three elements to the back of the queue, and put the first three elements on the back. All this is O(1), since the enqueue and dequeue operations are each O(1). The final while loop moves elements from front to back until d, the original first element, is again the first element. Since d is the third from last element when this loop is executed, it takes O(n) time and the total time is O(n).

• Question 6: Short Code Writing (10 points each)

a) Write a method ```public DogTeam merge (DogTeam other)``` to be added to the `DogTeam` class. If x and y are two `DogTeam` objects that are sorted by age, then `x.merge (y)` should return a team consisting of exactly the dogs from both x and y, also sorted by age. ("Sorted by age" means that each dog in the team has an age less than or equal to the dog following it.) You may assume that no individual dog appears in both teams. If either team is not sorted by age, the method should throw an `UnsortedException` -- assume that this exception class has been defined.

As we take elements off the lead of the two teams and put them onto a new team, we assemble the team we want backwards, which we can fix by reversing it after we are done.

``````
public boolean isBad ( ) {
// is the lead dog of this team older than the second dog?
if (size <= 1) return false;

public DogTeam merge (DogTeam other) {
DogTeam rev = new DogTeam( );
while (!this.isEmpty( ) && !other.isEmpty( )) {
throw new UnsortedException( );
if (this.getLeadNode( ).getElement( ).getAge( ) <
if (!this.isEmpty( )) {
if (other.isBad( )) throw new UnsortedException( );
while (!other.isEmpty( ))
while (!this.isEmpty( )) {
if (this.isBad( )) throw new UnsortedException( );
DogTeam ret = new DogTeam( );
while (!rev.isEmpty( ))
return ret;}
``````

b) Write a method `public boolean hasDuplicate( )` to be added to the `DogTeam` class. It should return two if any two of the dogs in the calling team are the same dog according to the `equals` method of the `SledDog` class. You may use any of the data structures defined by L&C, but not an iterator for `DogTeam` unless you write it. Your method should leave the calling `DogTeam` exactly as it was before the call.

``````
public boolean hasDuplicate( ) {
if (getSize( ) <= 1) return false;
ArraySet<SledDog> as = new ArraySet<SledDog>( );
while (cur != null) {
cur = cur.getNext( );}
return (getSize( ) == as.size( ));}
``````

• Question 7: Long Code Writing (20 points)

Your job here is to write code to maintain the waiting list for admission to a course. Students are stored as `Student` objects, and the roster of those students already in the course is stored as an object `roster` of type `SetADT<Student>`. The class `Student` has a `compareTo` method so that the "smallest" student in a collection is the one most eligible to fill a vacancy in a course.

You are to define a class `Waitlist` extending the class `ArrayOrderedList<Student>`, with these three methods:

1. a constructor `Waitlist ( )` that establishes an empty waiting list,
2. an instance method `addStudent (Student s)` that puts a new student into the list,
3. an instance method ```fillCourse (SetADT<Student> roster, int capacity)``` that takes students from the calling waiting list, in order of their eligibility, and adds them to `roster` until either (a) the size of `roster` reaches `capacity` or (b) the waiting list is empty. It is all right to add a student to `roster` who is already in the course -- the `SetADT` methods will ensure that there is no duplicate entry and that the size is maintained correctly.

``````
public class Waitlist extends ArrayOrderedList<Student> {
public Waitlist ( ) {super( );}