CS302 Midterm, Fall, 2016
James S. Plank
Answers and Grading
Question 1: 20 points
Part A: The links define the following instance of disjoint sets:
So, the answer is:
{ 0, 1, 3, 6, 7, 8, 11, 12, 13 }, { 2, 4, 9, 14 } {5, 13} { 10 }
Part B: Union by size. This is because the ranks[] entry of the heads
of the set are equal to the sets' sizes. They clearly don't equal the heights (e.g.
the height of the set rooted by 1 is not 9), and even if you used path compression,
there's no way to get a rank of 9 with this few elements.
Part C: See the picture:
- d.Find(0) = 1.
- d.Find(15) = 1.
- d.Find(14) = 2.
- d.Find(10) = 10.
- d.Union(1,2) = 1. This is because the rank of set 1 is bigger than
the rank of set 2, so node 1 becomes the parent and node 2 becomes the child.
Part D: The first thing we do is view the vector as a heap:
Now, you call percolate_down() on the nodes with 40, 46 and 71:
Next, you call percolate_down() on the nodes with 56 and 86:
And finally, you call percolate_down() on the root:
Print that out as a vector:
{ 5, 10, 68, 32, 16, 71, 75, 40, 56, 46, 20, 86 }
Doing this by calling Push() on each element of the vector is not only the
incorrect way to do it, it's a huge pain, as you have to call percolate_up()
11 times. If you did that, the proper answer was:
{ 5, 16, 10, 40, 20, 68, 71, 75, 46, 56, 32, 86 }
Grading:
- Part A: 4 points.
- Part B: 2.5 points.
- Part C: 7.5 points (1.5 points per answer)
- Part D: 6 points. You got 5 points if you did the Push() solution
correctly, and you got partial credit for valid heaps that didn't fit either paradigm
(and that had all the elements).
Question 2: 20 points
I reiterated during the test: I wanted the running time of the procedure. That is specified
clearly on the exam. That will be defined
by the running time of the most costly operation, but that doesn't mean it is equal to
the running time of the most costly operation. For example, in Proc_F(), the most
costly operation is the Pop() call, which is O(log n). However, you're calling
Pop() n times, so the running time of the procedure is O(n log n).
Grading here was 2 points per part. I gave some partial credit.
Also, I took off if your answers demonstrated that you didn't really "get" big-O -- answers
like O(n+3), or O(n/2), or O(n) + O(n2).
Grading
- 1 point per part.
- You get 0.5 points for answering k on part F.
- You get 0.5 points for answering j on part H.
- You get 0.2 points for answering r on part J.
- You get 0.3 points for answering l on part L.
- You get 0.3 points for answering j on part N.
Question 3: 20 points
Part A: This one follows the enumeration lecture notes. Let l be equal to
s.size(). You will enumerate all numbers
from 0 to ln-1, and treat each number like a n-digit
number in base l. You'll extract those digits with div and mod, and use
them as indices into s.
The program
q3.cpp implements proc() and also implements
a main() that allows you to specify n and s on the command line.
void proc(int n, string s)
{
int top;
int i, j, index;
/* Calculate the total number of strings. */
top = 1;
for (i = 0; i < n; i++) top *= s.size();
/* Now, enumerate a separate index for each string. You
will calculate the individual characters using div/mod,
as explained in the enumeration lecture notes. */
for (index = 0; index < top; index++) {
i = index;
for (j = 0; j < n; j++) {
printf("%c", s[i%s.size()]);
i /= s.size();
}
printf("\n");
}
}
|
UNIX> g++ -o q3 q3.cpp
UNIX> q3 2 a
aa
UNIX> q3 2 ab
aa
ba
ab
bb
UNIX>
|
UNIX> q3 2 abc
aa
ba
ca
ab
bb
cb
ac
bc
cc
UNIX>
|
UNIX> q3 3 ab
aaa
baa
aba
bba
aab
bab
abb
bbb
UNIX>
|
Part B: ln, where l equals s.size().
Grading
Part A was worth 16 points, and Part B was worth 4. If you gave the right answer for
Part B, but it didn't match your implementation, then you got 3 points.
I gave partial credit to power set enumerations, which typically got confused, because you
didn't know what to do with n.
Question 4: 16 points
The answers for both questions 4 and 5 are in q45.cpp.
Question 4 is straightforward bit arithmetic:
vector <int> do_transpose(vector <int> m)
{
vector <int> rv;
int i, j;
rv.resize(m.size(), 0);
for (i = 0; i < m.size(); i++) {
for (j = 0; j < m.size(); j++) {
if (m[i] & (1 << j)) {
rv[j] |= (1 << i);
}
}
}
return rv;
}
|
Grading:
- Resizing the return vector: 2 points.
- Having a double-nested for loop on m.size(): 2 points.
- Extracting the bits correctly: 4 points
- Setting the bits correctly: 4 points
- Getting i and j correct with the (have to be using bit arithmetic to get this): 4 points
As always, I gave partial credit.
Question 5: 20 points
Question 5 is a nuts and bolts program that uses sscanf() or stringstreams
to read the command
line and check the formatting. There are three errors that I can think of, and you should
test for each:
- The argument is not in the format "0x"-number-in-hex. You can test the
return value of sscanf() for that error.
- There are more than 32 arguments -- in that case, m is too big.
- The last one is subtle, but I included it in my example
-- if a number has any bits set that are greater
than the first m.size() bits, then that too is an error. For example,
if there are four elements in the matrix, and one of them is, say, 0x10, then
it has too many bits set (because 0x1f is equal to 10000 in binary). To
test for this, you can do a simple for loop that starts at (1 << m), and
stops at 0x80000000, using bit arithmetic to test to see if the bits are set.
I took an easier path below, by clearing those high order bits, and then testing
to see if the result equals the original.
int main(int argc, char **argv)
{
int i, v, mask;
vector <int> m;
vector <int> t;
/* Reading the command line. This loop was worth 12 points. */
for (i = 1; i < argc; i++) {
if (sscanf(argv[i], "0x%x", &v) != 1) {
printf("Bad command line argument %s\n", argv[i]);
exit(1);
}
m.push_back(v);
}
/* Too many words on the command line. Two points. */
if (m.size() > 32) {
printf("Too many items in m: must be <= 32\n");
exit(0);
}
/* Checking for stray bits. Two points. */
if (m.size() < 32) {
mask = (1 << m.size()) - 1;
for (i = 0; i < m.size(); i++) {
if ((m[i] & mask) != m[i]) {
printf("Bad item -- 0x%x -- too many bits set.\n", m[i]);
}
}
}
/* Call do_transpose and print. Four points. */
t = do_transpose(m);
for (i = 0; i < t.size(); i++) printf("0x%x\n", t[i]);
return 0;
}
|
Grading:
- Looping from 1 to argc: 2 points
- Looping from 0 to argc: 1 point
- Reading from standard input rather than the command line: 0.5 points
- Reading the "0x": 1 point
- Reading the hex correctly using sscanf() or a stringstream: 5 points.
- Printing an error if there is no "0x": 2 points
- Printing an error if the number is not proper hex: 2 points
- Printing an error when there are more than 32 words: 2 points
- Printing an error when stray bits are set: 2 points
- Calling do_transpose(): 1 point
- Outputting a line per element of the vector: 1 point
- Outputting proper hex: 1 point
- Outputting the "OX": 1 point