Question text is in black, solutions in blue.
Q1: 24 points Q2: 20 points Q3: 20 points Q4: 16 points Q5: 20 points Total: 100 points
Questions 2 and 5 refer to the following class whose objects are nodes in a linked list -- this is the same class used on the first midterm:
public class LLNode<T> {
private LLNode<T> next;
private T contents;
public LLNode (T x)
{contents = x; next = null;}
public void setContents (T x) {contents = x;}
public T getContents( ) {return contents;}
public void setNext (LLNode<T> t) {next = t;}
public LLNode<T> getNext( ) {return next;}
}
LIFO means "last in first out" and is used by stacks. FIFO means "first in first out" and is used by queues.
mystery(45)
produce given the method below? (Note: Copyrighted example taken
from
the CSE 143 Web at the University of Washington Department of
Computer
Science and Engineering.)
public static void mystery (int n) {
if (n <= 1) {
System.out.print(": ");}
else {
System.out.print((n % 2) + " ");
mystery (n/2);
System.out.print(n + " ");
}
}
The correct output string is "1 0 1 1 0 : 2 5 11 22 45 ". There are five recursive calls to the method after the original one, with parameters 22, 11, 5, 2, and 1 respectively. The last call produces ": ", and each of the earlier calls produces a 0 or 1 before making its call and its parameter afterward. The bits in front come in order of the calls, and the numbers after come in reverse order of the calls.
Deques may only add or remove elements at either end, while lists may do so anywhere. Note that this question refers to the definition of the classes, not to their implementation, so that any answer referring to links among nodes or pointers is necessarily wrong.
When two copies of a synchronized method in different threads act on the same data, they do so sequentially, so that the second method does not begin until the other has finished. This prevents any interference from overlapping execution of the two methods on the same data.
Barking
class below
produce any output? If so, how many lines of output?
public class Cardie implements Runnable {
public void run ( ) {
while (true) System.out.println("Woof!");}}
public class Barking {
public static void main (String [ ] args) {
Runnable r = new Cardie( );
Thread t = new Thread(r);
t.start( );}}
The new thread is created and then is terminated when the main method reaches the end of its code. Between the time of its creation and the time of its termination, the new method will print as many lines of output as it can. This might be none, one, or more than one, because we cannot predict in advance how much time the operating system will allocate to the new thread before it dies. So we can't tell whether there is output at all, or how many lines there will be.
==
, equals
, and
compareTo
. What are the differnences among these
three types of comparison?
The ==
operator on objects returns a boolean that is true if
and only if the two sides of the operator reference the same object in memory.
The equals
method returns a boolean that is true if and only if
the calling object and the parameter have the same value, according to a method
written for the class. (If no such method is written for the class or for any
of its superclasses, the method of the Object class runs and returns the same
answer as ==
.) The compareTo
method is defined for
certain classes only -- it returns an int value that is negative if the calling
object is "less than" the parameter, 0 if it has the same value, and positive
if it is "greater than" the parameter.
No. The recursion can be avoided, but there is no way to solve the n-disk Tower of Hanoi puzzle without using at least 2n disk moves. So any recursive or iterative method must use at least O(2n) steps to produce the desired output, and the method from Project #3 achieves this time bound.
ArraySortedList
to make the contains
and get
methods each run in O(log n) time instead of
O(n) time? (Note: The version of this question given in the
actual test also incorrectly said that remove
could
be similarly sped up.)
Both contains
and get
use the find
method to locate the matching entry or confirm its non-existence. We can
replace the linear search in DJW's find
method with a binary
search and thus spend only O(log n) time on that method. The remaining
code of get
and contains
takes only O(1), so the
total is O(log n). (The remove
method takes O(n) in the worst
case to move elements after a successful removal, so improving find
to O(log n) does not change its total running time of O(n).)
LLNode<T>
class defined
above)
public boolean hasT (LLNode<T> p, T elem) {
// returns true if any element equal to elem
// is in the linked list headed by p
if (p == null) return false;
if (p == elem) return true;
return hasT (p,getNext( ), elem);
}
The variables p
and elem
are of different types,
since the first is a node and the second a T
object.
So applying
The answer I (Dave) posted here is wrong, because Java does
allow the use of ==
to them in the fifth line is a type error and the code will
not compile.==
between any two objects. It
compares the references, returning true only if the two sides
refer to the same object. The error here is that p ==
elem
will never be true, so this method will never
return true, and so will give the wrong output in cases where an
element equal to elem
exists in the list.
The programmer presumably intended to say
if (p.getContents( ) == elem) return true
.
public T dequeue( ) {
if (isEmpty( ))
throw new QUE ("dequeue from empty");
else {
T toReturn = queue[front];
queue[front] = null;
front++;
numElements--;
return toReturn;
}
}
This is not a circular array implementation because there is no wraparound
of addresses at the end. So the array will run out of room once the total
number of operations (rather than the size of the queue) exceeds its size.
At that point there will be an ArrayIndexOutOfBoundsException
.
public class Animal {
public void bar( ) {
System.out.println("bar");}}
public class Dog extends Animal {
public void foo( ) {
System.out.println("foo");
super.foo( );}}
This will not compile. The call to super.foo( )
would only
work if the superclass Animal
had a method called foo
with the correct signature, and it does not.
LLNode<T>
class defined above)
public T antepenult( ) {
// returns contents of third node from last
// in linked list headed by this node
// returns null if there is no such node
if (this == null) return null;
if (this.getNext( ) == null) return null;
if (this.getNext( ).getNext( ) == null) return null;
if (this.getNext( ).getNext( ).getNext( ) == null)
return this.getContents( );
return antepenult (this.getNext( ));
}
This will not compile. In the last line, the method antepenult
is called with a parameter, but it is only defined with no parameter. The
correct call would be this.getNext( ).antepenult( )
.
int largestDigit(long
n)
that accepts an integet parameter and returns the
largest digit value that appears in the decimal string
representing that integer. (Note: This problem also taken
(slightly adapted) from UW CSE's CSE 143 Web.)
If a number's string contains only a single digit, that digit's value is by definition the largest. Here are some examples of desired results:
largestDigit (14263203) returns 6
largestDigit (845) returns 8
largestDigit (52649) returns 9
largestDigit (3) returns 3
largestDigit (0) returns 0
largestDigit (-573026) returns 7
largestDigit (-2) returns 2
For full credit, obey the following restrictions in your solution:
String
,
Scanner
, array, or any data structure such as a
list or stack.
Hint: In Java, 345 % 10
is 5 and 345
/ 10
is 34. However, -42 / 10
is -4 and
-42 % 10
is -2. If you don't like these latter
facts, don't use %
on negative numbers (it's
pretty easy to avoid doing so).
public static int largestDigit (long n) {
Many of you wanted to remember the "largest digit seen so far" as you
traversed the string. This could be done by declaring an instance variable
outside the method, as in Question 4d, but we only asked you to write the
method itself. You could have this method call a helper method that took
the largest digit so far as a second parameter. But many of you declared
a variable inside the recursive method and expected it to persist in other
copies of the method, not realizing that every new call to the method causes
a separate copy of each local variable.
public static int largestDigit (long n) {
if (n < 0) return largestDigit(-n);
if (n < 10) return n;
int r = n % 10;
int digit = largestDigit(n / 10);
if (digit >= r) return digit;
return r;}
Stack<String>
object, that simulates this
recursive method. Your method should have the same output as
the recursive one for any int
input. It is
possible to design a simple iterative algorithm that gives
this output without using a stack. But we want you to
use a stack, ideally to directly simulate the action of the
recursuve method.
public static String triangle (int n) {
if (n == 0) return ("");
String out = "";
out = "*" + triangle (n - 1);
System.out.println (out);
return out;
}
public static String iterativeTriangle (int n) {
public static String iterativeTriangle (int n) {
Stack<String> s = new Stack<String>( );
while (n != 0) {
s.push("*");
n--;}
String out = "";
while (!s.empty( )) {
out += s.pop( );
System.out.println(out);}}
Every square is checked at least once, but it is only visited at most once because the recursive code only calls itself on unseen land squares. So there is O(1) time spent on each of the n2 squares, for O(n2) time in all.
int fun (int n) {
if (n <= 0) return 1;
return fun (n-1) + fun(n-1);
}
Each call makes two calls on the function with parameter one smaller, so that
there are finally 2n calls on fun(0)
. Each call takes
O(1) time apart from waiting for its recursive calls to finish. The total
number of calls at all levels of the recursion is 1 + 2 + ... + 2n =
O(2n), so the total running time is O(2n).
int anotherFun (int n) {
if (n <= 0) return 0;
return anotherFun (n/2) + n;
}
Here there is O(1) time spent at each level of recursion, since there is only one call at each level. The depth of the recursion is O(log n), since that is the number of times n must be halved before reaching 0. So the total running time is O(log n).
get
and
set
methods of ArrayList
each take
O(1) time.)
ArrayList<Integer> m = new ArrayList<Integer>( );
int fib(int n) {
if (n <= 1) {
m.set(n, n);
return m.get(n);}
Integer f = m.get(n);
if (f == null) {
f = fib(n-1) + fib (n-2);
m.set (n, f);}
return f;
}
This method computes the Fibonacci numbers by "memoizing" -- each entry of the array is filled in with the correct Fibonacci number the first time this is calculated, and then this entry is used in the future in place of that number being recalculated. Only O(1) time is spent to compute each number, so the total time is O(n).
LinkedUnbndQueue<T>
that implements a
queue using a linked list, made up of nodes from the
LLNode<T>
class defined above. All
methods must run in O(1) worst-case time. You may assume
that the exception class
QueueUnderflowException
has alredy been
defined.
public class LinkedUnbndQueue<T>
implements UnboundedQueueInterface<T> {
protected LLNode<T> front, rear;
// four methods below will go here
}
public LinkedUnbndQueue ( ) {
Though note that blank code is also correct for this constructor,
as the two new instance methods are intitialized to
public LinkedUnbndQueue ( ) {
front = rear = null;}
null
by default.
public boolean isEmpty ( ) {
public boolean isEmpty ( ) {
return (front == null);}
public void enqueue (T element) {
public void enqueue (T element) {
LLNode<T> newNode = new LLNode<T>(element);
if (rear == null)
front = newNode;
else rear.setNext(newNode);
rear = newNode;}
public T dequeue ( ) {
public T dequeue ( ) {
if (isEmpty( ))
throw new QueueUnderflowException("Dequeue from empty");
else {
T toReturn = front.getContents( );
front = front.getNext( );
if (front == null)
rear = null;
return toReturn;}}
Last modified 12 November 2014.