81 terms

# CS314 Midterm IClicker Qs

###### PLAY
Cons lst = null;
for (int i = 0; i < n; i++ )
lst = append( lst, list(i) );
What is the Big O of this code?

A: O(1)
B: O(n)
C: O(n log n)
D: O(n2)
E: error

This code is a trap for the unwary: the Big O of append is the size of its first argument, but the size of the first argument is growing as the loop progresses. This sets up a Bermuda Triangle situation that leaves our ship lost in an O(n2) whirlpool.
Cons lst = null;
for (int i = 0; i < 3; i++ )
lst = cons( i, lst );
lst = nreverse(lst);
What is the value of lst?

A: (1 2 3)
B: (3 2 1)
C: (0 1 2 3)
D: (0 1 2)
E: (2 1 0)

cons builds the list backwards compared to the order of item creation. nreverse reverses it, using the same Cons cells ("Read my lips: No new Conses!"), putting the result into forward order.
Cons lst = null;
for (int i = 0; i < n; i++ )
lst = cons( i, lst );
lst = nreverse(lst);
What is the Big O of this code?

A: O(1)
B: O(n)
C: O(n log n)
D: O(n2)
E: error

The cons is always O(1), inside a loop of n, so the loop is O(n). nreverse is also O(n). O(n) + O(n) = O(n).

Rule: If the order in which you cons up a list makes it come out backwards, nreverse it at the end.
Cons lst = null;
for (int i = 0; i < 3; i++ )
lst = cons( i, lst );
What is the type of first(lst) as seen by the compiler?

A: int
B: Integer
C: short
D: Cons
E: Object

The int value i gets coerced to Integer by the compiler before doing the cons. A smart compiler might infer that the first(lst) would now be Integer, but the Java compiler is rather stupid and only knows the declared type of first(), which is Object. If we want to use the type of first(lst), we will have to cast it as ((Integer) first(lst)).
What is
(intersection '(c r e a m) '(s u g a r))
A: (C E M S U G A R)
B: (C E M S U G)
C: (A R) or (R A)
D: true
E: false

intersection returns the elements that are present in both sets, in any order since sets are unordered.
What is (union '(c r e a m) '(s u g a r))
A: (C E M S U G A R)
B: (C R E A M S U G A R)
C: (A R)
D: true
E: false

union returns the elements that are present in either set, in any order since sets are unordered. There are no duplicate elements.
What is
(set-difference '(c r e a m) '(s u g a r))
A: (C E M S U G A R)
B: (M E C)
C: (S U G)
D: (A R)
E: (C E M S U G)

set-difference returns the elements that are present in the first set, but not in the second set, in any order.

set-difference often confuses students: it is not symmetric (commutative); unique elements of the second set do not appear in the output.
What is (intersection '(r a t) '(f i n k))
A: (R A T)
B: (F I N K)
C: (R A T F I N K)
D: null
E: false

These two sets have nothing in common, so the intersection is the empty set, which is represented as null. (false would be a type error, since false is boolean .)
What is (set-difference '(r a t) '(f i n k))
A: (T A R)
B: (K N I F)
C: null
D: true
E: (R A T F I N K)

set-difference returns the elements that are present in the first set, but not in the second. Since the two sets are disjoint, the answer is the first set, perhaps re-ordered.
Suppose we perform the following operations on a Stack: (push 1) (push 2) (push 3) (pop) (pop) (push 4) (pop) (pop)
What is the order of the items that come out?
A: 1, 2, 3, 4
B: 4, 3, 2, 1
C: 2, 3, 1, 4
D: 3, 2, 4, 1
E: 2, 3, 4, 1

push and pop both operate at the top of the stack only. If we use a list as the stack, with the top of stack at the left, the successive operations are:

initial: stack = ()
(push 1) stack = (1)
(push 2) stack = (2 1)
(push 3) stack = (3 2 1)
(pop) stack = (2 1), 3 is produced
(pop) stack = (1), 2 is produced
(push 4) stack = (4 1)
(pop) stack = (1), 4 is produced
(pop) stack = (), 1 is produced
What is the Big O of set intersection, done well?
A: O(1)
B: O(n)
C: O(n log n)
D: O(n2)
E: O(n3)

Set intersection can be done well by sorting both sets, O(n log n), then using the merge technique, O(n), to form the intersection.

If the sets are subsets of a finite and small set of possibilities, the intersection could be done by an and (&) operation on bit vector representations of the sets, which would be much faster.
Suppose we perform the following operations on a Queue: (insert 1) (insert 2) (insert 3) (remove) (remove) (insert 4) (remove) (remove) What is the order of the items that come out?
A: 1, 2, 3, 4
B: 4, 3, 2, 1
C: 2, 3, 1, 4
D: 3, 2, 4, 1
E: 2, 3, 4, 1

We said that queues are British, hyper-polite, boring: with a queue, the answer is always 1, 2, 3, 4 ... regardless of what the question is.
Suppose that we say:

ArrayList<Integer> lst = ...;
int sum = 0;
for (int i = 0; i < lst.size(); i++ )
sum += lst.get(i);
What is the Big O of this code?

A: O(1)
B: O(n)
C: O(n log n)
D: O(n2)
E: O(n3)

Since ArrayList is basically an array in its implementation, the .get(i) operation is O(1).
int sum = 0;
for (int i = 0; i < lst.size(); i++ )
sum += lst.get(i);
What is the Big O of this code?

A: O(1)
B: O(n)
C: O(n log n)
D: O(n2)
E: O(n3)

Because LinkedList requires stepping down the list to find the requested element, the .get(i) operation is O(i). Since i is growing within the loop, this sets up a Bermuda Triangle situation, giving a time of O(n2).
int sum = 0;
for (Integer i : lst )
sum += i;
What is the Big O of this code?

A: O(1)
B: O(n)
C: O(n log n)
D: O(n2)
E: O(n3)

Using the for-each loop with the : is convenient, involves less code, and has a good Big O for both LinkedList and ArrayList.
Is every thing in the empty list (null) a number?
A: Yes: Got to be good-looking 'cause it's so hard to see.
B: No: There is nothing in the empty list that could be a number.
C: Maybe: Depends on the implementation.
D: Error: null is an improper argument to every.
E: WTF: I thought this was CS, not Philosophy.

every is an and over a set of items: every(p, lst) = p(lst1) && p(lst2) && ... && p(lstn) = p(lst1) ∧ p(lst2) ∧ ... ∧ p(lstn) .

The base case (identity or idempotent value) for and is true, since (x && true) = x, so every should return true as its base case when the list is empty.
Is some thing in the empty list (null) a number?
A: Yes: Got to be good-looking 'cause it's so hard to see.
B: No: There is nothing in the empty list that could be a number.
C: Maybe: Depends on the implementation.
D: Error: null is an improper argument to every.
E: WTF: I thought this was CS, not Philosophy.

some is an or over a set of items: some(p, lst) = p(lst1) || p(lst2) || ... || p(lstn) = p(lst1) ∨ p(lst2) ∨ ... ∨ p(lstn) .

The base case (identity or idempotent value) for or is false, since (x || false) = x, so some should return false as its base case when the list is empty.
What is the Java corresponding to this tree?
go check the website for the picture, #42

A: z = y + 3 * x
B: z = x * y + 3
C: z = (3 + y) * x
D: z = (y + 3) * x
E: z = x * (y + 3)

There are several things to remember in order to get this right:

An operator goes together with its children. Thus, + must connect y and 3.
Order: the expression must have the same left-to-right order as the tree: y + 3, not 3 + y.
Precedence: since + has lower precedence than , a + expression in the scope of a operator must be parenthesized.
Which of the following are advantages of the first-child / next-sibling representation of trees?
A: faster execution
B: promotes family values
C: unlimited number of children
D: saves memory
E: C and D

C is true because first-child / next-sibling in effect gives each node a linked list of children; thus the number of children is unlimited. D is true because each node contains only 2 links, making it use less storage than a representation that stores a link for each child if there can be more than 2 children per node.
What is the Big O of finding an item in a balanced BST?
A: O(1)
B: O(log n)
C: O(n)
D: O(n log n)
E: O(n2)

A BST, or Binary Search Tree, is ordered so that all descendants to the left of a node have a key value that is less, and all descendants to the right of a node have a key value that is greater. Thus, a search can discard half the tree at each step, giving a O(log n) search time.
What kind of tree is most similar to our directory tree? (p. 134)
A: Binary tree
B: n-ary tree
C: BST
D: First-child / next-sibling
E: Implicit tree

The directory tree used in the class notes, p. 134, is like a first-child / next-sibling tree because each node has a linked list of its children.
What is the order in which nodes of this tree are visited in depth-first order?
go check the website for the picture, #46

A: Z, =, Y, *, A, +, X
B: =, Z, +, *, X, Y, A
C: Y, A, *, X, Z, +, =
D: =, Z, +, *, Y, A, X
E: Z, Y, A, *, X, +, =

In depth-first order, a node is visited and then its children are visited in order (same as preorder).
What is the order in which nodes of this tree are processed in inorder?
go check the website for the picture, #47

A: Z, =, Y, *, A, +, X
B: =, Z, +, *, X, Y, A
C: Y, A, *, X, Z, +, =
D: =, Z, +, *, Y, A, X
E: Z, Y, A, *, X, +, =

In inorder, the parent is processed in between its children. For this tree, that gives the same order as Java source code (infix).
What is the order in which nodes of this tree are processed in postorder?
go check the website for the picture, #48

A: Z, =, Y, *, A, +, X
B: =, Z, +, *, X, Y, A
C: Y, A, *, X, Z, +, =
D: =, Z, +, *, Y, A, X
E: Z, Y, A, *, X, +, =

In postorder, the parent is processed after its children, producing a Polish postfix order for this expression.
What is the order in which nodes of this tree are processed in preorder?
go check the website for the picture, #49

A: Z, =, Y, *, A, +, X
B: =, Z, +, *, X, Y, A
C: Y, A, *, X, Z, +, =
D: =, Z, +, *, Y, A, X
E: Z, Y, A, *, X, +, =

In preorder, a node is processed prior to its children.
Why do binary search trees need to be balanced?
A: saves search time
B: saves memory
C: easier to draw
D: unbalanced trees may cause errors
E: A, B, and C
Balancing of a BST is important to give the desired O(log n) search time. If the tree is unbalanced, search time could be as bad as O(n). While O(n) is not always bad, we expect a lookup table to have a time of O(1) or O(log n) because lookup is done frequently, often in a loop. (Unless the table is known to be small, in which O(n) is okay.)
What would the branching factor b need to be for a tree with n = 1,000,000,000 elements at the bottom to have a height (depth) d of 3?
A: 2
B: 10
C: 30
D: 100
E: 1000

Our formula for trees is n = b d.

Thus, we have 1,000,000,000 = b3, which gives b = 1,000.

A large branching factor, as found in B-trees, allows a desired record to be found in a large database with a small number of (slow) disk accesses. If the first 2 levels of this tree are kept in memory (1,000 + 1,000,000 items), any record in the billion-record database can be gotten with a single disk access.

Contents Page-10 Prev Next Page+10 Index
About how long does it take to read a record from a disc drive?
A: 10 microseconds (0.00001 second)
B: 100 microseconds (0.0001 second)
C: 1 millisecond (0.001 second)
D: 10 milliseconds (0.01 second)
E: 100 milliseconds (0.1 second)

Disk access takes around 10 milliseconds, 1/100 of a second. While this seems fast, a computer can execute millions of instructions in this amount of time. Thus, disk access can easily become a bottleneck, which is why it takes so long to boot up your computer.
If we divide a 1 TB disc drive equally among all possible social security numbers, how many bytes are there per SSN?
A: 10
B: 100
C: 1000
D: 10,000
E: 100,000

A terabyte is 1012 bytes. There are 9 digits in a SSN, hence 109 possible SSN's. Dividing gives 103 bytes per SSN.

If we compute a disk address directly from the SSN, we can access the record for any SSN with one (slow) disk access.

Although not all SSN's are valid, disk space is cheap, so it is okay to waste some of it.
What is the value of (list("a") == list("a"))
A: true
B: false
C: null
D: error
E: could be true or false

Today's Zen question: What is the meaning of == ?

The meaning of the == for reference types (any Capital-letter type in Java such as String) is: exact equivalance of pointer values, i.e. same location in memory.

Any call to cons(), list(), or new allocates brand-new storage, different from any existing storage that might be pointed to. Since there are two calls to list(), each one gets its own brand-new storage, and they are guaranteed to be in different locations.
What is the value of
(subst 'crazy 'beauty '(beauty is as beauty does))
A: (crazy is as crazy does)
B: null
C: (crazy is as beauty does)
D: (beauty is as beauty does)
E: (beauty is as crazy does)

(subst x y z) means "substitute x for y in z". It replaces all occurrences.
What is the value of
(sublis '((z 4) (y 3) (x 2)) '(* x y))
A: error
B: (* x y)
C: (* x 3)
D: 6
E: (* 2 3)

sublis makes a copy of its second argument, replacing variables with their values as given in the association list that is the first argument.
What is the value of (list("a").equals(list("a")))
A: true
B: false
C: null
D: error
E: could be true or false

In general, .equals() compares the values of two reference types (as opposed to ==, which compares locations, or exact identity). Since these two objects have equal values, .equals() returns true.
What is the value of
(match '(- ?x ?y) '(- w 3)) ?
A: ((?y 3))
B: true
C: false
D: null
E: ((?y 3) (?x w))

(match pattern input ) compares the pattern and input, returning a binding list or association list of variable substitutions that, if made, would cause the pattern to be equal to the input (or null if there is no such substitution).

The rules for match are:

Constant values and structure in the pattern must match exactly.
Variables (beginning with ?) will match anything,
but they must do so consistently.
What is the value of
(match '(- ?x ?x) '(- w 3)) ?
A: ((?x w))
B: true
C: false
D: null
E: ((?x 3) (?x w))

The pattern does not match the input, because to do so would require ?x to match both w and 3.

The answer returned is null, which can be of the specified return type, Cons. (false is type boolean, so it would cause a compiler error.)
What is not true of .hashCode() in Java?
A: there is a default .hashCode() for any Object
B: returns an int
C: must be the same for objects that are .equals()
D: could be negative
E: is usually a prime

We often use a prime number as the size of a hash table and compute the hash value modulo that prime. The .hashCode(), though, is any int and usually will not be a prime.
Keeping the load factor (fullness) λ < 0.7 in a hash table:
A: means there usually are no collisions
B: keeps the number of collisions fairly small on average
C: wastes between 1 / 3 and 1 / 2 the table space
D: requires use of quadratic probing
E: B and C

With λ < 0.7 there will be some collisions (about 1 on average), but this can be considered to be constant-time. Keeping the table less than 0.7 full means we are wasting 0.3 of the space at least, basically between 1 / 3 and 1 / 2.
What is the Big O of hashing when λ < 0.7 ?
A: O(1)
B: O(log n)
C: O(n)
D: O(n log n)
E: O(n2)

Although we expect some collisions (about 1 on average), this can be considered to be constant-time.
What is an advantage of hashing with buckets, compared to ordinary hashing?
A: faster Big O
B: don't need to expand the table
C: simpler code: no collisions
D: A and B
E: B and C

Hashing with buckets uses an an array of pointers to an extra structure, such as a linked list, to store all entries that hash to a given value.

The extra structure means we don't have to worry about collisions (there are none) or expanding the table. The Big O, formally, may be worse: O(n) instead of O(1) because it takes O(n) time to search down the linked list; with a fairly large table to hash into, though, this can be made small in practice.
What is the Big O of hashing with buckets?
A: O(1)
B: O(log n)
C: O(n) but you can make it very fast
D: O(n log n)
E: O(n2)

The formal answer is O(n) due to the time to search linearly through the linked list that is used for a bucket.

In reality, though, the average time is n / (2 * nb) where nb is the number of buckets. By making the number of buckets large enough, say n / 10, we can make the search time small enough to be considered constant.
Suppose that items are inserted into a min priority queue with the order and priorities: ((A, 2), (B, 3), (C, 1), (D, 2), (E, 1))
In what order are the items removed from the queue?

A: A, B, C, D, E
B: C, E, A, D, B
C: B, A, D, C, E
D: E, C, D, A, B
E: C, E, D, A, B

After the insertions, the queue will contain:

1: C, E
2: A, D
3: B
The priority 1 items will be processed in order, followed by Priority 2 and 3.
What are advantage(s) of a heap for storing a priority queue, compared to an AVL tree?
A: faster Big O
B: simpler code
C: uses less memory
D: A and B
E: B and C

A heap involves relatively simple code, compared to the complex code to handle an AVL tree. The heap also saves memory: whereas the AVL tree has two pointers and a balance code for each node, the heap uses an array and can compute pointers from array indexes; thus it uses no storage for pointers.
What is the data structure used for a heap?
A: a hash table
C: an AVL tree
D: an array that we think of as a tree
E: a list that we think of as an array
What is not true about Insertion Sort?
A: stable
B: O(n log n)
C: on-line
D: in-place
E: good when input is almost sorted

Insertion Sort is O(n2), but is good when the input is almost sorted. It is also stable (does not change the relative position of equal keys), on-line (able to accept new items one at a time and process them efficiently), and in-place (does not need large extra storage).
A: stable
B: always O(n log n)
C: on-line
D: in-place
E: best for small input

Quicksort is usually great. But it is not stable (it swaps items), can be O(n2) in the worst case, is not on-line (accepting a new item means sorting the whole set again), and is not that good for small input (recursive function calls are relatively expensive for the small cases). It is in-place, sorting within the original array.
A: stable
B: always O(n log n)
C: on-line
D: in-place
E: B and D
The number of possible graphs with n nodes is:
A: n
B: n^2
C: n^3
D: 2^n
E: 2^n^2

Whoa! This is huge. There are 65,536 possible graphs with 4 nodes, and 33,554,432 possible graphs with 5 nodes.

If we think about the adjacency matrix representation of a graph, there is an n × n matrix with a 0 or 1 in position [i][j] iff there is an arc from i to j. Since there are n^2 bits, the number of values of all possible matrices of bits is 2^n^2
Suppose that each user of Facebook has 1000 friends.
Is that graph:

A: sparse
B: dense
C: acyclic
D: planar
E: k-chromatic

A graph is sparse if the number of edges is O(v) where v is the number of vertices. All real-world graphs are sparse unless they are very small.

In this question, the number of edges is O(1000 * v); that is O(v) even though 1000 is a big number.
Consider a family tree (ancestry) as a graph, with links from parents to their children.
Is that graph:

A: sparse
B: dense
C: acyclic
D: directed
E: A, C, and D

The graph is sparse (people don't have many children), acyclic (nobody is their own ancestor), and directed (from parents to children).
What does Prim's algorithm guarantee?
A: Distance between any two cities is no more than twice the shortest path between them
B: If two cities have a direct edge connecting them, the path between them will use it
C: Total distance to connect all nodes is minimized
D: Total distance between pairs of nodes is minimized
E: Nodes that are too far away are not connected
What does Dijkstra's algorithm produce?
A: Shortest paths from one node to all other nodes
B: Shortest path between any pair of nodes
C: Shortest path from one node to one goal node
D: Minimum total distance of all paths
E: Minimum average distance between any pair of nodes
What advantage might A* have over Dijkstra's Algorithm?
A: Lower-cost route than Dijkstra
B: Finds same answer as Dijkstra for one goal with less work
C: Gets answers nearly as good but runs faster
D: Finds paths between more pairs of nodes
E: Has a stronger guarantee of optimality

For some applications (e.g. driving directions) a path to one goal is all that is needed.
What does A* assume that Dijkstra does not?
A: sum of all edge costs is to be minimized
C: limited number of edges per node
D: routes to many destinations are needed
E: a heuristic estimate of cost from a node to goal

A* takes advantage of a heuristic function to search faster. While a heuristic of 0 could be used, that would be the same as Dijkstra.
What is true of heuristic functions for A*?
A: must be within a factor of 2 of true cost
B: even an inaccurate heuristic can be useful
C: cannot underestimate cost
D: must obey the Pythagorean theorem
E: always nonzero

Even a crude and inaccurate heuristic can still reduce search time significantly.
What kind of problem is MapReduce good for?
A: large matrix calculations
B: O(2n) algorithms
C: combining bits of data from many diverse sources
D: simple calculations over massive amounts of data
E: all of the above

MapReduce isn't good for everything. The key to using MapReduce for an application is to conceptualize the application as one or a sequence of simple operations, perhaps over massive data. Handling massive data with many computers is where MapReduce excels.
A program consists of an O(n) loop followed by another O(n) loop. What is the Big O of the program?

A: O(n) + O(n)
B: 2 O(n)
C: O(2 n)
D: O(n)
E: O(n2)

If there is a section of sequential code:

{ s1;
s2;
...
}

the Big O is the max of the Big O of the statements.

Constants are not included in Big O, which means answers A, B, C should be reduced to O(n).
What is log(student wealth) / log(Bill Gates wealth) ?

A: 1/1000
B: 1/10
C: 1/5
D: 1/3
E: 1/2

A good way to approach this question is to take the log2, i.e. find the number of bits required to represent the number.

We use our rule that 1000 ≅ 10 bits.

Assume that a student has \$8,000 and Bill Gates has \$50,000,000,000. Representing student wealth requires 13 bits: 10 bits for 1,000 and 3 bits for 8 (23 = 8). Representing Bill Gates' wealth requires 36 bits: 3 * 10 bits for 1,000,000,000 and 6 bits for 50 (26 = 64).

Thus, in terms of log2, a student has a bit more than 1/3 of what Bill Gates has.

It is also easy to do this problem by counting digits in decimal: \$8,000 is 4 digits, while \$50,000,000,000 is 11 digits. 4 is a bit more than 1/3 of 11.

The lesson: log grows very slowly.
How many bits are there in a word on your computer?

A: 8
B: 16
C: 32 / 64
D: thousands
E: millions
C
For over 20 years, most of the world's computers have used a 32-bit word, particularly in the Intel IA-32 architecture.

The word size is important, because it is:

the width of the communication path between the memory and CPU
the number of bits that the CPU does an operation on at one time
32 bits is also enshrined as the size of int and Integer in Java.

The Intel Core i5 and similar processors have a 64-bit word, but also have a 32-bit compatibility mode; even if you have one of these more modern processors, it is likely that much of what you do is running in 32-bit mode.
Can the national debt (in dollars) be represented in an int or an Integer?

A: neither
B: int
C: Integer
D: both
E: WTF
A
The national debt is over \$15,000,000,000,000.

We use our rule that 1000 ≅ 10 bits.

The national debt requires 44 bits: 4 * 10 bits for 1,000,000,000,000 and 4 bits for 15 (24 = 16).

Both int and Integer are 32 bits, which can represent ± 2,147,483,647, not even close to the national debt.
When a program's time is plotted on log-log paper, the curve is not a straight line, but curves upward. The program is probably:

A: O(n)
B: O(n log n)
C: O(n2)
D: O(n3)
E: O(2n)

Polynomial-time programs (those whose Big O is O(nk) for some constant k) will plot as straight lines on log-log paper. A factor of log n will probably not be noticeable.

If a program's time curves upward on a log-log plot, it is probably intractable, exponential, NP-complete, O(2n), and very bad news: unless your problem is very small, you will not be able to solve it with any amount of computers.

However, some important NP-complete problems have polynomial-time approximate solutions that are pretty good.
When the size of a program's input is increased by 2, the runtime increases by 8. The program is:

A: O(n)
B: O(n log n)
C: O(n2)
D: O(n3)
E: O(2n)

When the input size increases by 2 and the time increases by x, the Big O is O(nk) where x = 2k. In this case, 8 = 23, so the program is O(n3).
Integer costs 4 times as much storage as int (16 bytes for an Integer, 4 bytes for an int).
What benefit does Integer provide?

A: More accuracy
B: Useful methods
C: Can use e.g. with ArrayList
D: All of the above
E: B and C only

int and Integer have exactly the same accuracy, 32 bits.

Integer is the same as int, except that Integer comes in a really nice box. The box is so nice that it costs 3 times as much as the product inside.

If we want to use a parameterized Java container such as ArrayList, we must use Integer: only a reference type can be used as a type parameter.

Integer also has useful methods. Only a reference type can have methods.

int is a low-cost, bare-bones integer, which is useful for local variables within the program and cases where there is a large array and we want to save storage. ``
An Integer is immutable (its value cannot be changed).

Suppose we do:

Integer i = 3;
Integer j = i;
i++;
System.out.println("i = " + i + ", j = " + j);

What values are printed?

A: i = 4, j = 4
B: i = 4, j = 3
C: i = 3, j = 4
D: i = 3, j = 3
E: error

Since Integer is an immutable reference type, it is stored in a box containing a value that is unchanged after the box has been created.

The variables i and j do not contain the numeric values, but contain pointers to boxes that contain the values. Initially, i and j point to the same box, containing 3.

What can Java do in response to i++? It cannot change the 3 value inside the box, since it is immutable. Instead, Java must find or make a new box containing the value 4. After the statement i++, i points to this new box, while j still points to the old box containing 3.

Java caches boxes for small integers so that it does not have to make a new box every time.
Suppose we have an array myarray of length n, and we say:

int n = myarray.length;

What is the Big O of this statement?

A: O(1)
B: O(n)
C: O(n log n)
D: O(n2)
E: depends on the item type of myarray

An Array is a reference type, which contains its .length as a stored value. We can tell that .length is a stored value rather than a method because it has no parentheses after it.

Rule: any stored .field of a reference type can be accessed in O(1) time.
Suppose that we say:

int [] myarray = new int[1000];

About how many bytes are used by (a) the variable myarray, and (b) what it points to?

A: 1000 and 1000
B: 4000 and 4000
C: 8 and 1000
D: 8 and 4000
E: 1000 and 4000

myarray is a reference variable, so it contains only a pointer to the actual value. Pointers are 8 bytes on a more modern machine.

Each int is 4 bytes; since there are 1000 of them, the total is 4000 bytes. There is some additional storage in the array for storing the Array class designation, .length, and hash code; this is small compared to the bulk of the array.
Integer [] myarray = new Integer[1000];
for (int i = 0; i < 1000; i++)
myarray[i] = new Integer(i);

About how many bytes are used by (a) the variable myarray, (b) what it points to, and (c) the total storage allocated by this code?

A: 8000, 8000 and 16000
B: 8, 8000 and 24000
C: 8, 8000 and 16000
D: 1000, 8000 and 9000
E: 1000, 8000 and 25000

The variable myarray is a reference variable, so it has the pointer size, 8 bytes.

The array is an array of pointers, so it is about 8000 bytes.

The pointers point to individual Integer objects, each of size 16 bytes, so these occupy 16000 bytes.
Suppose that we say:

double three = 3.0;
double point3 = 0.3;

What can we say about the stored values?

A: Both values are represented exactly.
B: Both values are represented approximately.
C: three is exact, point3 is approximate.
D: three is approximate, point3 is exact.
E: Depends on which CPU chip is used.

Integers are represented exactly in floating point, up to the limits of the mantissa accuracy (about 15 digits for double).

Decimal fractions usually cannot be represented exactly in binary. Just as 1/3 = .3333333... in decimal, 1/10 is an infinitely repeating pattern in binary. Therefore, any floating-point number with nonzero digits after the decimal is probably represented as an approximation in binary.

Floating point representation is governed by an IEEE Standard, which all CPU chips follow. Therefore, the representation of a floating-point value will be the same no matter which CPU chip is used.
What is (cons '(a) '(b)) ?

A: (a b)
B: ((a) (b))
C: ((a) b)
D: ((a b))
E: error

cons adds one new item to the front of a linked list: (cons 'a '(b c)) = (a b c).

In this case, the new item is a sublist, (a).

Rule: In (cons '(a) '(b)), that is (cons first rest), move the left paren of the rest argument to the left of the first argument; that is the answer.
What is (first '((a b) (c d))) ?

A: a
B: (a b)
C: ((a b))
D: null
E: error

first returns the first thing in a list; a "thing" is a simple item, such as a symbol (string) or number, or a balanced pair of parentheses including everything inside, no matter how big.
What is (rest '((a b) (c d))) ?

A: ((b) (c d))
B: (c d)
C: (b (c d))
D: ((c d))
E: null

rest returns the rest of a list after the first thing.

In the parenthesized notation, move the opening parenthesis to the right past the first thing; that is the answer. Moving the opening paren past (a b) leaves ((c d)).
What is (rest (rest '((a b) (c d)))) ?

A: (() (c d))
B: (c d)
C: ((c d))
D: null
E: error

(rest (rest ... )) moves the opening paren to the right past 2 things; in this case, that leaves () or null.
What is (length '((a b) (c d)) ) ?

A: 1
B: 2
C: 3
D: 4
E: 5

length returns the length of a list at top level; this is a list of 2 things, (a b) and (c d), so the length is 2.
What is (reverse '((a b) (c d)) ) ?

A: ((b a) (d c))
B: ((b a) (c d))
C: ((c d) (a b))
D: ((d c) (b a))
E: ((a b) (c d))

reverse reverses the top level of a list, leaving the insides of elements unchanged.
Suppose that we say:

Cons lst = null;
for (int i = 0; i < 3; i++ )
lst = cons( i, lst );

What is the value of lst?

A: (1 2 3)
B: (3 2 1)
C: (0 1 2)
D: (2 1 0)
E: (((2) 1) 0)

cons puts one new item onto the front of an existing linked list.

Because of this, it builds a list in backwards order compared to the order of insertion.

As the loop proceeds, the value of lst is:

() initially
(0)
(1 0)
(2 1 0)
Suppose that we say:

Cons lst = null;
for (int i = 0; i < 3; i++ )
lst = cons( i, lst );

What is the runtime type of first(lst)?

A: int
B: Integer
C: null
D: Cons
E: Object

The declared type of first(lst) is Object. When this code says cons(i, lst), the compiler coerces the int value i into the reference type Integer. Integer (a subtype of Object) is what first(lst) actually is at runtime.
What is (append '(a b) '(c d)) ?

A: ((a b) (c d))
B: (a b c d)
C: (a b (c d))
D: ((a b c d))
E: ((a b) c d)

append concatenates two lists at top level, making a single list that contains the elements of the two input lists.

append makes a copy of the first input list, and reuses the second input list.
Cons lst = append(x, y);

and that x has length n and y has length m.

What is the Big O of this statement?

A: O(n)
B: O(m)
C: O(n + m)
D: O(n) + O(m)
E: O(n2 + m2)

append makes a copy of the first input list, and reuses the second input list. Therefore, its Big O depends only on the size of the first input. The Big O is O(n) because the first input list is copied, one element at a time.
Suppose that we say:

Cons lst = list("a", "b", "c");
boolean test = ( lst == reverse(reverse(lst)) );

What is the value of test?

A: true
B: false
C: null
D: error
E: could be true or false

reverse makes a backward copy of its input. What == does, for any reference types, is to compare equality of pointer values, i.e., do the two pointers reference the same numeric address in memory? Since reverse(reverse(lst)) is a backward copy of a backward copy, it resides at a different address than the original.
Suppose that we say:

Cons lst = list( list("a", "b"), list("c", "d"));
boolean test = ( first(lst) ==
first(reverse(reverse(lst))) );

What is the value of test?

A: true
B: false
C: null
D: error
E: could be true or false

reverse operates at the top level of a list only, i.e. it makes a backward copy of the input list, but does not modify the objects that the list contains. reverse(reverse(lst)) is a backwards copy of a backwards copy, so it is a copy of the original in the original order. The first item of the copy is exactly the same item as in the original, so the pointers are equal in numeric value and are ==.
Suppose that we say:

Cons lst = null;
for (int i = 0; i < 3; i++ )
lst = append( list(i), lst );

What is the value of lst?

A: (1 2 3)
B: (3 2 1)
C: (0 1 2 3)
D: (0 1 2)
E: (2 1 0)

This code is adding the item i to the front of the list (in a somewhat wasteful fashion: lst = cons( i, lst ) would do the same thing).
Suppose that we say:

Cons lst = null;
for (int i = 0; i < n; i++ )
lst = append( list(i), lst );

What is the Big O of this code?

A: O(1)
B: O(n)
C: O(n log n)
D: O(n2)
E: error