Download as pdf or txt
Download as pdf or txt
You are on page 1of 6

Eric Roberts Handout #36

CS106B February 9, 2011


Answers to Midterm Exam

Congratulations! As a class, you knocked this one out of the park. So, I have to
conclude either that the exam was way too easy or that most of you are really on top of
the material. Given the independent corroborative evidence from the section leaders who
tell me that things are going well, Im going to assume its the latter and set the median at
a very high letter grade, pegging the median in the A range rather than my usual target
of having it be the lowest B+. The complete histogram appears on page 2, but here are a
few noteworthy statistics:

N = 271
Median = 54.0
Mean = 52.1

The scale to letter grades looks like this:

Grade Range N
A+ 5960 31
A 5658 74
A 5455 44
B+ 5253 31
B 4951 31
B 4648 23
C+ 4345 14
C 4042 8
C 3639 5
D 3035 3
NP 0029 7
2

Histogram

56
56
56
56
56
56
56
56
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
56 59
53 56 58
53 56 58
53 55 58
53 55 58
53 55 58
53 55 58
53 55 58
53 55 58
53 55 58
53 55 58
53 55 58
53 55 58
52 55 58
52 55 58
52 55 58
52 55 58
52 55 58
52 55 58
52 54 58
52 54 58
52 54 58
52 54 58
47 52 54 58
47 50 52 54 57
47 50 52 54 57
47 50 52 54 57
47 50 52 54 57
47 50 52 54 57
47 50 52 54 57
47 50 52 54 57
47 50 52 54 57
46 50 51 54 57
46 50 51 54 57
46 50 51 54 57 60
46 49 51 54 57 60
46 49 51 54 57 60
46 49 51 54 57 60
44 46 49 51 54 57 60
44 45 49 51 54 57 60
41 44 45 48 51 54 57 60
41 44 45 48 51 54 57 60
41 44 45 48 51 54 57 60
40 43 45 48 51 54 57 60
38 40 42 45 48 51 54 57 60
17 23 28 35 37 39 42 45 48 51 54 57 60
17 22 24 28 31 33 37 39 42 45 48 51 54 57 60


3
Problem 1: Tracing C++ programs and big-O (10 points)
This problem requires tracing out the two recursive functions, at least far enough to
understand what is happening. The Enigma function is an elaborate way of returning the
value of its argument, although it does a linear amount of work to do so. The Mystery
function itself adds the result of Enigma(n), which is simply n, to the result of calling
Mystery(n - 1). If you trace this through, you quickly find that, for example,

Mystery(4) = 4 + Mystery(3)
!
3 + Mystery(2)
!
2 + Mystery(1)
!
1 + Mystery(0)
!
0

This decomposition therefore indicates that Mystery(4) is 4 + 3 + 2 + 1 + 0 or 10. In
general, the value of Mystery(N) is therefore

N + N1 + N2 + . . . + 3 + 2 + 1

or



The most frequently executed operation in this computation is the == test in the if
statement in Enigma (or, equivalently, the + sign a few lines further on). These operators
are executed once for each value of 1 that gets added to the emerging total. The overall
complexity is therefore

O(N
2
)

after applying the conventional simplifications of eliminating the low-order terms and
removing constant factors.

N
2
+ N
2
4
Problem 2: Vectors, grids, stacks, and queues (10 points)


/*
* Function: Reshape
* Usage: Reshape(grid, nRows, nCols);
* -----------------------------------
* Changes the dimensions of the grid (in the manner of resize) in a
* way that retains the values of the original elements in the grid.
* The values from the old grid are assigned to the new grid by
* proceeding through the grid in row-major order. The loop ends
* whenever the elements of the old grid or the spaces in the new
* grid are exhausted.
*/

void Reshape(Grid<int> & grid, int nRows, int nCols) {
Grid<int> oldGrid = grid;
grid.resize(nRows, nCols);
int row = 0;
int col = 0;
foreach (int value in oldGrid) {
if (!grid.inBounds(row, col)) break;
grid[row][col] = value;
col++;
if (col == nCols) {
col = 0;
row++;
}
}
}


There are many other possible solutions. Here, for example, is one that uses a queue to
store the old values:



void Reshape(Grid<int> & grid, int nRows, int nCols) {
Queue<int> values;
foreach (int element in grid) {
values.enqueue(element);
}
grid.resize(nRows, nCols);
for (int i = 0; i < nRows && !values.isEmpty(); i++) {
for (int j = 0; j < nCols && !values.isEmpty(); j++) {
grid[i][j] = values.dequeue();
}
}
}



5
Problem 3: Lexicons, maps, and iterators (15 points)

/*
* Function: Update
* Usage: Update(dict, changes);
* -----------------------------
* Updates the contents of dictionary by going through each entry
* in changes, which is a map from old words to new ones. For each
* such word, Update eliminates the old word and replaces every
* occurrence in other definitions with the corresponding new word
* from the change map.
*/

void Update(Map< Vector<string> > & dict, Map<string> & changes) {
foreach (string key in changes) {
ReplaceWord(dict, key, changes[key]);
}
}

/*
* Function: ReplaceWord
* Usage: ReplaceWord(dict, oldWord, newWord);
* -------------------------------------------
* Applies the redefinition phase of the Update algorithm to a
* single oldWord/newWord pair. Implementation note: It is
* important that the code avoid copying the vector of words
* in an existing definition because changing that copy would
* leave the original vector unchanged.
*/

void ReplaceWord(Map< Vector<string> > & dict, string oldWord,
string newWord) {
dict.remove(oldWord);
foreach (string entry in dict) {
int nWords = dict[entry].size();
for (int i = 0; i < nWords; i++) {
if (dict[entry][i] == oldWord) {
dict[entry][i] = newWord;
}
}
}
}



6
Problem 4: Recursive functions (10 points)

/*
* Function: RemoveDoubledLetters
* Usage: string shorter = RemoveDoubledLetters(str);
* --------------------------------------------------
* Removes all but the first of a sequence of identical letters
* from str.
*/

string RemoveDoubledLetters(string str) {
if (str.length() <= 1) {
return str;
} else if (str[0] == str[1]) {
return RemoveDoubledLetters(str.substr(1));
} else {
return str[0] + RemoveDoubledLetters(str.substr(1));
}
}


Problem 5: Recursive procedures (15 points)

/*
* Function: TryAllOperators
* Usage: TryAllOperators(exp, target);
* ------------------------------------
* Recursively replaces every ? in the expression by each of the
* primary arithmetic operators (+, -, *, /). If the resulting
* expression evaluates to the target integer, the function
* prints out the expression string that generated it. This
* function is a simple wrapper; the recursive function divides
* up the string one character at a time, keeping track of the
* previously considered characters in prefix.
*/

void TryAllOperators(string exp, int target) {
RecTryAllOperators("", exp, target);
}

void RecTryAllOperators(string prefix, string rest, int target) {
if (rest == "") {
if (EvaluateExpression(prefix) == target) {
cout << prefix << endl;
}
} else if (rest[0] == '?') {
rest = rest.substr(1);
RecTryAllOperators(prefix + "+", rest, target);
RecTryAllOperators(prefix + "-", rest, target);
RecTryAllOperators(prefix + "*", rest, target);
RecTryAllOperators(prefix + "/", rest, target);
} else {
RecTryAllOperators(prefix + rest[0], rest.substr(1), target);
}
}

You might also like