CMPSCI 187: Quick Solutions to Midterm Exam #2 1) Java Concepts a) The recursive method computes n! by multiplying n by (n-1)!, the latter computed by a recursive call. The iterative method sets x = 1 and then does x *= i for all i from 1 to n, using a for loop. b) LLNode is a node for a singly linked list with a link pointer. DLLNode is a node for a doubly linked list that also has a back pointer. Both have info fields of type T. c) A serializable class has objects that can be written directly to a file by a writeObject method, and read back with readObject. An unserializable class' objects must be converted to strings or primitives before being written to a file, and this output must be parsed when read back. d) A synchronized method cannot overlap execution with another version of the same method in another thread. It locks variables down until it is finished. An unsychronized method could overlap in this way, both threads modifying the same variables, possibly with unintended consequences. e) A sorted list always has it elements in ascending order according to the compareTo method in the elements' class. An unsorted list can have its elements in any order and need not have comparable elements. The add method in an unsorted list, for example, puts the new element in the right place according to the order. 2) Software Engineering a) Yes, we could if we set up a queue as int he centrality test of Project #4, and marked every node as visited when it went onto the queue. We will mark every node on the continent by the time the queue is empty. We could then give the marked nodes the correct continent label. b) Make sure that no square can go on the queue more than once. Then count the squares as they come off the queue. Since we put every square of the continent on the queue exactly once each, we get the number of squares in our counter when the queue is empty. Note that since there is no time we are sure that all the squares are on the queue, we can't just get the size of the queue at any time -- we must count them going on or going off. c) When a customer is dequeued for a server, we need to determine whether they gave up before reaching the front of the queue. If they were in the queue for k seconds, they had k/10 chances to give up. We create a Random object, ask it for k/10 numbers using nextInt(100), and see whether any of those numbers are 0. If so, we don't serve the customer and move on -- if not we serve the customer. 3) Tracing Code a) recurse (3,3) = recurse (2, 4) = recurse (1, 5) = recurse (0, 6) = 1 + recurse (0, 5) = 2 + recurse (0, 4) = … = 6 + recurse (0, 0) = 6 + 7 = 13. b) Lines 3-5 create three nodes L, C, and D. Lines 6-8 set them up L --> C --> D --> L. Line 9 makes L point to D. Line 10 makes C point to L. Line 11 makes D point to itself. So we have C --> L --> D --> D and the for loop sets cur to D, so what is printed is "Duncan". c) Start with q = CB, r = DA. Each of the three passes through the loop takes the two front elements off the queues and puts them back with the smaller element in q. So the first move makes q = BC, r = AD, the second makes q = CA, r = DB, and the third makes q = AB, r = BD. We print "Ace" and "Cardie" on separate lines. 4) Finding Errors a) This won't compile because the variable "list" is not declared in the main method, either as a local variable or an instance variable. (It is declared in the constructor and thus dies when the constructor finishes.) b) The intended error is that if this method is called with j = 0 and k > 0, it will never reach a base case and thus never return a result, violating the postcondition even though the precondition is true. There is also an unintended error, a missing right paren in the last line. c) The intended error is that the variable totalAge is declared inside the while loop and used outside it -- the code will not compile. There is also an unintended error in that on line 9 "cur" should be declared as "LLNode" instead of just "LLNode" -- this would also cause it not to compile. Many of you thought there was an error causing the while loop not to terminate, but there isn't. Saying "list = dNode" just moves the pointer "list". It doesn't affect the node with the "null" info field, which is still linked from cNode and is still found by the while loop. 5) Timing Analysis a) The queue q is filled with N elements which are eventually taken off, but we only take an element off of q every other time through the loop. (By the end of the code r will have "Cardie" N times and "Duncan" N times, alternating.) But only O(1) operations are done each time an element comes off of q, so the while loop is O(N), and everything else is O(1) or O(N), so the whole fragment is O(N). b) The inner loop shifts all the elements from q to r, then shifts all but one of the elements back. So q, which starts with N elements, will have N, N-1, N-2, etc., on successive trips through the outer loop. So the outer loop will execute N times, and the inner loop takes O(N), so we have O(N^2) total time. c) The two while loops take the contents of q, shift them to r with a new element after each one, then shift the result back to q. Thus the size of q doubles each time through the outer loop, going from 1 to 2 to 4 and so on to reach 2^N after the N executions of the outer loop. The time of the inner loop is proportional to the number of elements of q at the start. So the total time is O(1 + 2 + … + 2^N) = O(2^N). There was an unintended error in this code -- line 3 should be q.enqueue("Cardie") 6) Short Coding public Board solution ( ) { if (isBad( )) return null; // calling board is bad, no solution int row, col; for (row = 0; row < 9; row++) for (col = 0; col < 9; col++) if (getEntry(row, col) == 0) break; // now (row, col) is the first location with a 0 in the calling board if (row == 9) return this; // calling board is the desired solution for (int val = 1; val <= 9; val++) { Board b = move (row, col, val); if (b.solution( ) != null) return b.solution( );} return false; // no entry for (row, col) led to a solution } 7) Long Coding public class License implements Comparable { int number; Person owner; Dog d; // getters and setters, constructor public boolean equals (License other) { return (this.getNumber( ) == other.getNumber( );} public int compareTo (License other) { int ours = this.getNumber( ); int theirs = other.getNumber( ); if (ours < theirs) return -1; if (ours == theirs) return 0; return 1;}} public class LicenseDatabase { public ListInterface list; public LicenseDatabase( ) { list = new ArraySortedList ( );} public boolean addNew License (int number, Person owner, Dog d) { License lic = new License (number, owner, d); if (list.contains(lic)) return false; list.add (lic); return true;} public boolean removeLicense (int target) { list.reset( ); for (int i = 0; i < list.size( ); i++) { License entry = list.getNext( ); if (entry.getNumber( ) == target) { list.remove (entry); return true;} return false;} public License findDog (Dog d) { list.reset( ); for (int i = 0; i < list.size( ); i++) { License entry = list.getNext( ); if (entry.getDog( ).equals(d)) return entry; return null;}}