These solutions are in beta! Please post corrections as a follow-up to the Piazza post.
UC Berkeley – Computer Science
CS61B: Data Structures
Midterm #1, Spring 2018
This test has 7 questions worth a total of 160 points, and is to be completed in 110 minutes. The exam is closed book, except that you are allowed to use one double sided written cheat sheet (front and back). No calculators or other electronic devices are permitted. Give your answers and show your work in the space provided. Write the statement out below in the blank provided and sign. You may do this before the exam begins.
“I have neither given nor received any assistance in the taking of this exam.”
Meow meow meow meow meow mooo meow meow purr.
# 0 1 2 3 4 5
Points # Points 0.75 6
Signature: _____Nibbles_____________ Name: __Nibbles________________
SID: ___8675309_________________
Three-letter Login ID: _nib_____
Login of Person to Left: _jos____
Login of Person to Right: _hug___
Exam Room: _779 Soda__________
20 197 23
12 16.25 39
30
TOTAL 160
Tips:
• •
• •
• • • •
There may be partial credit for incomplete answers. Write as much of the solution as you can, but bear in mind that we may deduct points if your answers are much more complicated than necessary. There are a lot of problems on this exam. Work through the ones with which you are comfortable first. Do not get overly captivated by interesting design issues or complex corner cases you’re not sure about.
Not all information provided in a problem may be useful.
Unless otherwise stated, all given code on this exam should compile. All code has been compiled and executed before printing, but in the unlikely event that we do happen to catch any bugs in the exam, we’ll announce a fix. Unless we specifically give you the option, the correct answer is not ‘does not compile.’
○ indicates that only one circle should be filled in.
□ indicates that more than one box may be filled in.
For answers which involve filling in a ○ or □, please fill in the shape completely.
When the exam says “write only one statement per line”, a for loop counts as one statement.
Optional. Mark along the line to show your feelings Before exam: [L___x________________J]. on the spectrum betweenLandJ. After exam: [L________________x___J].
Clarifications:
4c. Removes all y from x. Returns first node in x that is not y. May not use new. Destructive. This is just a clarification and does not change the problem.
6b. …the method below so that it prints out returns
7b. There should not be an @Override tag.
7b. You can assume x is non-null.
One of your TAs, Kevin Lin, has made wonderful walkthrough videos for you:
UC BERKELEY Login: _nib___
2
CS61B MIDTERM, SPRING 2018
Login: _______
0. So it begins (0.75 points). Write your name and ID on the front page. Write the exam room. Write the IDs of your neighbors. Write the given statement. Sign when you’re done with the exam. Write your login in the corner of every page. Enjoy your free half 3⁄4 pointJ.
1. Static Dada.
a) (10 points) Consider the class shown below. Next to the lines with blanks, write the result of the print
statement. No syntax errors or runtime errors occur.
public class Dada {
private Dada[] r;
private static Dada[] rs;
private String name;
public Dada(String n) { name = n; }
/** Prints out the given array, i.e. if d contains two Dadas
* with names “alice” and “bob”, this method will print “alice bob”. */ private static void printDadaArray(Dada[] d) {
for (int i = 0; i < d.length; i += 1) {
System.out.print(d[i].name + " "); }
System.out.println();
}
public static void main(String[] args) {
} }
Dada a = new Dada("alice");
Dada b = new Dada("bob");
Dada c = new Dada("carol");
Dada d = new Dada("dan");
Dada[][] twod = {{a, b}, {c, d}}; // and the second {c, d}
a.r = twod[1];
printDadaArray(a.r);
Dada.rs = a.r;
b.r = Dada.rs;
b.r = new Dada[]{d, c};
Dada.rs[1] = new Dada("eve");
printDadaArray(Dada.rs);
printDadaArray(b.r);
printDadaArray(twod[0]);
printDadaArray(twod[1]);
// carol dan
// carol eve
// dan carol
// alice bob
// carol eve
// reminder from lecture:
// twod = {{a, b}, {c, d}} creates
// an array of Dada arrays where
// the first array contains {a, b}
3
UC BERKELEY Login: _nib___
b) (9 points) Suppose we add new methods to Dada called fillOne and fillMany and replace main as shown below. Fill in the print statements. The Dada class is otherwise unchanged.
private static void fillMany(Dada[] d) {
System.arraycopy(rs, 0, d, 0, d.length);
// Reminder, arraycopy parameters are:
// (Dada[] from, int start, Dada[] to, int destination, int num)
}
private static void fillOne(Dada d) { d = rs[0];
}
public static void main(String[] args) { Dada a = new Dada("alice");
Dada b = new Dada("bob");
Dada c = new Dada("carol");
Dada d = new Dada("dan");
Dada[][] twod = {{a, b}, {c, d}};
Dada.rs = new Dada[]{new Dada("fritz"), new Dada("gritz")};
c.r = twod[0];
printDadaArray(c.r);
fillOne(c.r[0]);
printDadaArray(c.r);
fillMany(c.r);
printDadaArray(c.r);
// alice bob
// alice bob
// fritz gritz
}
For your convenience, the instance variables of Dada were:
private Dada[] r; private static Dada[] rs; private String name;
4
CS61B MIDTERM, SPRING 2018
Login: _______
2. What It Do (12 Points).
a) Consider the code below.
public static int f(int x) { if (x == 1) {
return 1; }
return 2 * f(x / 2);
}
Describe as succinctly as possible what this method does when executed for all possible values of x. If the behavior is different depending on x, describe the behavior in every interesting case. Remember that integer division in Java rounds down, i.e. 3/2 yields 1.
For x >= 1, prints out the largest power of 2 that is smaller than x. For x < 1, goes into infinite loop.
b) Consider the code below.
public static void g(IntList x) { if (x == null) { return; } g(x.rest);
x.rest = x;
}
Draw a box and pointer diagram that shows the result of executing the following two lines of code. If any objects are not referenced by anything else (i.e. are garbage collected), you may omit drawing them if you prefer. If you need it, the IntList definition is on page 7. If g never finishes because it gets stuck in an infinite loop, write “Infinite Loop” instead of drawing a diagram.
IntList L = IntList.of(3, 4, 5); //creates an IntList containing 3, 4, and 5
g(L);
5
UC BERKELEY Login: _nib___
3. KeyGate (16.25 points). Suppose we have the classes defined below, with 3 lines marked with UK, USK, and UF.
public class FingerPrint {...}
public class Key { ... }
public class SkeletonKey extends Key { ... }
public class StandardBox { public void unlock(Key k) { ... } } // UK
public class BioBox extends StandardBox {
public void unlock(SkeletonKey sk) { } // USK public void unlock(Fingerprint f) { } // UF
}
For each line below, fill in exactly one bubble. If a line causes an error, assume it is commented out before the following lines are run.
public void doStuff(Key k, SkeletonKey sk, Fingerprint f) { StandardBox sb = new StandardBox();
StandardBox sbbb = new BioBox();
BioBox bb = new BioBox();
sb.unlock(k);
sbbb.unlock(k);
○○○○○ ○○○○○
bb.unlock(k); ○○○○○
sb.unlock(sk);
sbbb.unlock(sk);
bb.unlock(sk);
sb.unlock(f);
sbbb.unlock(f);
bb.unlock(f);
bb = (BioBox) sbbb;
((StandardBox) bb).unlock(sk);
((StandardBox) sbbb).unlock(sk);
((BioBox) sb).unlock(sk);
}
○○○○○ ○○○○○ ○○○○○
○○○○○ ○○○○○ ○○○○○
○ ○ ß Leave blank if no error ○○○○○ ○○○○○ ○○○○○
Compile
Error
UK USK UF
Runtime
Error Runs
Runs Runs
6
CS61B MIDTERM, SPRING 2018
Login: _______
4. Sans. Implement the methods below. For reference, the IntList class is defined on the following page.
a) (9 points). /** Non-destructively creates a copy of x that contains no y. */ public static int[] sans(int[] x, int y) {
int[] xfirst = new int[x.length];
int c = 0;
for (int i = 0; i < x.length; i += 1) {
if (x[i] != y) {
xfirst[c] = x[i];
c = c + 1;
} }
int[] r = new int[c];
System.arraycopy(xfirst, 0, r, 0, c);
return r;
}
b) (9 points). /** Non-destructively creates a copy of x that contains no y. */
public static IntList ilsans(IntList x, int y) {
if (x == null) {
return null;
}
if (x.first == y) {
return ilsans(x.rest, y);
}
return new IntList(x.first, ilsans(x.rest, y));
}
c) (9 points). /** Destructively creates a copy of x that contains no y. You may not use new. */
public static IntList dilsans(IntList x, int y) {
if (x == null) {
return null;
}
x.rest = dilsans(x.rest, y);
if (x.first == y) {
return x.rest;
}
return x; }
7
UC BERKELEY Login: _nib___
d) (12 points). Suppose we want to write tests for ilsans and sans. Fill in the code below with a JUnit test that each method behaves as expected for one example input. Do not write a test for null inputs. Reminder that IntList.of(4, 5, 6) creates an IntList containing the values 4, 5, and 6. Assume the methods on the previous page are all part of a class called Sans, i.e. they are invoked as Sans.sans.
import org.junit.Test;
import static org.junit.Assert.*;
public class TestSans {
@Test
public void testSans() { // TEST THE ARRAY VERSION OF SANS
}
int[] x = {1, 2, 3, 4, 5, 6, 2, 2, 3, 3};
int y = 2;
int[] expected = {1, 3, 4, 5, 6, 3, 3};
int[] actual = sans(x, y);
assertArrayEquals(expected, actual);
@Test // TEST THE NON-DESTRUCTIVE INTLIST VERSION OF SANS public void testIlsans() {
IntList x = IntList.of(1, 2, 3);
int y = 2;
IntList expected = IntList.of(1, 3);
IntList actual = Sans.ilsans(x, y);
assertEquals(expected, actual);
assertNotEquals(x, actual); // x should not have been altered
For reference, part of the IntList class definition is given below: public class IntList {
public int first;
public IntList rest;
public IntList(int f, IntList r) {
first = f;
rest = r; }
public IntList() {}
public static IntList of(Integer... args) { /* works correctly */ } public boolean equals(Object x) { /*works correctly w/ assertEquals*/ }
}
}
8
CS61B MIDTERM, SPRING 2018
Login: _______
5. A Needle in ArrayStack. The Stack interface is given below. A Stack is basically like the proj1 Deque, where push is like “addLast”, and pop is like “removeLast”. For example, if we call push(5), push(10), push(15), then call pop(), we’d get 15. If we call pop() again, we get 10.
public interface Stack
void push(Item x); // places an item on “top” of the stack
Item pop(); // removes and returns “top” item of the stack int size(); // returns the number of items on the stack
}
a) (14 points). Fill in the ArrayStack implementation below. To ensure efficient memory usage, double the array size when full, halve the array size when < 1⁄4 full, and avoid storing unnecessary references. The if conditions for resizing during push and pop are provided for you.
public class ArrayStack
private int size;
public ArrayStack() { // initial array size should be 8 items = (Item[]) new Object[8];
size = 0;
}
private void resize(int capacity) {
Item[] newItems = (Item[]) new Object[capacity];
System.arraycopy(items, 0, newItems, 0, size);
items = newItems;
}
public void push(Item x) {
if (usage_ratio() == 1) { resize(size * 2); } items[size] = x;
size += 1;
}
public Item pop() {
if (size == 0) { return null; }
if (usage_ratio() < 0.25 && items.length > 8) {resize(items.length / 2);}
size = size – 1;
Item returnItem = items[size];
items[size] = null;
return returnItem;
}
public int size() { return size; }
private double usage_ratio() { return ((double) size()) / items.length; }
}
9
UC BERKELEY Login: _nib___
b) (18 points) Suppose we want to add a default method purge(Item x) to the Stack interface that eliminates all instances of x from the Stack, but leaves the stack otherwise unchanged. When comparing two items, remember to use .equals instead of ==. You may not assume items are non-null.
For example, suppose if we create a Stack and call push(1), push(2), push(3), push(2), push(2), push(2), then call purge(2), the stack would be reduced to size 2, and would have 3 on top and 1 on the bottom.
You may use an ArrayStack. For this problem and assume it works correctly, even if you didn’t finish part a or are unsure of your answer. You may not explicitly instantiate any other class or any array of any kind, e.g. no new LinkedListDeque<>(), new int[], etc.
public interface Stack
Item pop();
int size();
default void purge(Item x) {
} }
if (size() == 0) {
return;
}
Item top = pop();
purge(x);
if (!x.equals(top)) {
push(top); }
Or less elegant solution:
ArrayStack
while (size() > 0) {
Item next = pop();
if (!x.equals(next)) {
as.push(next);
}
}
while (as.size() > 0) {
push(as.pop());
}
Midterm 1 Leisure Region. Please relax and have a nice time in this region.
Nibbles is hoping that you’re having a good time. –>
10
CS61B MIDTERM, SPRING 2018
Login: _______
6. Combine. The Combine.combine method takes a ComFunc and an integer array x and uses the ComFunc to “combine” all the items in x. For example, if we have an implementation of ComFunc called Add that adds two integers, and we call combine using the Add class on the array {1, 2, 3, 4}, the result will be 10, since 1 + 2 + 3 + 4 is 10.
a) (16 points). Fill in the combine method below. If the array is of length 0, the result should be 0, and if the array is of length 1, the result should be the number in the array. For full credit use recursion. For 75% credit, you may use iteration. You may create a private helper function in the space provided. public interface ComFunc {
int apply(int a, int b); // apply(a, b) must equal apply(b, a)
}
public class Combine {
public static int combine(IntBinaryFunction f, int[] x) {
if (x.length == 0) {
return 0;
}
if (x.length == 1) {
return x[0];
}
int t = f.apply(x[0], x[1]);
return combine(f, x, t, 2);
}
private static int combine(IntBinaryFunction f, int[] x, int t, int k) {
if (k == x.length) {
return t; }
t = f.apply(x[k], t);
return combine(f, x, t, k + 1);
}
Or less elegant solution:
private static int combineAlt(IntBinaryFunction f, int[] x) {
int t = f.apply(x[0], x[1]);
for (int i = 2; i < x.length; i += 1) {
t = f.apply(x[i], t);
}
return t; }
b) (4 points). Suppose we have a method that adds two numbers, as shown below.
public class Add implements ComFunc { public int apply(int a, int b) {
return a + b;
11
} }
Fill in the method below so that it prints out the correct result. You may use your answer from part a. Even if you left part a blank or think it be incorrect, you can assume that everything works as expected.
public static int sumAll(int x[]) { // sumAll is not a member of Combine return Combine.combine(new Add(), x);
}
UC BERKELEY Login: _nib___
12
CS61B MIDTERM, SPRING 2018
Login: _______
7. The Downside of Default. Consider the ListOfInts interface below. addLast, get, and size behave exactly as your Deque interface from project 1A. set(int i, int value) sets the ith integer in the list equal to value. plusEquals adds each int in x to the corresponding int in the current list, i.e. if we call have a list L = [2, 3, 4] and we call L.plusEquals([5, 6, 7]), then after the call is complete, L will contain the values [7, 9, 11]. If the lists are not of the same length, plusEquals should have no effect.
a) (6 points). Fill in the plusEquals method below. public interface ListOfInts {
public void addLast(int i);
public int get(int i);
public int size();
public void set(int i, int value);
default public void plusEquals(ListOfInts x) { // assume x is non-null
} }
if (this.size() != x.size()){ return; }
for (int i = 0; i < size(); i += 1) {
this.set(i, this.get(i) + x.get(i));
}
b) (10 points). The DLListOfInts class stores a doubly linked list of integers, similar to your LinkedListDeque class. Assume that the list has a single sentinel node that points at itself when the list as empty, just like in lecture and in the recommended approach for proj1a. Fill in the plusEquals method so that it behaves as in part a. You must use iteration. You cannot call super.plusEquals. public class DLListOfInts implements ListOfInts {
public class IntNode {
public int item;
public IntNode next, prev;
}
private IntNode sentinel;
private int size;
public void plusEquals(DLListInt x) {
if (x == null || this.size() != x.size()) {
return;
}
IntNode xPtr = x.sentinel.next;
for (IntNode p = sentinel.next; p != sentinel; p = p.next) {
} } ...
p.item += xPtr.item;
xPtr = xPtr.next;
13
UC BERKELEY Login: _nib___
c) (7 points) The method sumOfLists given below is supposed to take an array of DLListOfInts and returns a DLListOfInt that is equal to the element-wise sum of all of the lists. For example if the array contains three lists that hold [2, 2, 2], [1, 2, 3], and [3, 3, 3], respectively, the method should return a DLListOfInts that contains [6, 7, 8]. The method should be non-destructive.
public class PartC {
/** Non-destructively computes the sum of the given lists. Assumes
* that all lists are of the same length and that none are null. */
public static DLListOfInts sumOfLists(DLListOfInts[] lists) {
ListOfInts result = lists[0];
for (int i = 1; i < lists.length; i += 1) {
result.plusEquals(lists[i]);
}
return result;
}
}
What mistakes (if any) are there in sumOfLists? Note: The fact that the method makes the listed assumptions (lists are not null and are all of same length) is not a bug, it’s an assumption.
- Return type is upcast from result, so the code will not compile.
- A 0-length array input will cause an ArrayIndexOutOfBoundsException.
- It’s destructive.
- (quadratic runtime is out of scope, but acceptable answer) result.plusEquals calls the default
plusEquals (in ListOfInts), a slower implementation which results in a quadratic runtime.
8. PNH (0 points). What two catastrophic events are believed to be responsible for the creation of almost all the gold on the earth?
- Massive meteorite shower
- Collision between neutron stars
14