The document discusses the results of a midterm exam for a CS106B class. It provides statistics on exam scores including the median score of 54.0, mean of 52.1, and a breakdown of letter grades. It then discusses the solutions to 5 problems on the exam involving tracing recursive functions, vector and grid operations, dictionaries and maps, recursive string functions, and recursively trying arithmetic operators. The highest scored problem involved tracing two recursive functions and analyzing their time complexity.
The document discusses the results of a midterm exam for a CS106B class. It provides statistics on exam scores including the median score of 54.0, mean of 52.1, and a breakdown of letter grades. It then discusses the solutions to 5 problems on the exam involving tracing recursive functions, vector and grid operations, dictionaries and maps, recursive string functions, and recursively trying arithmetic operators. The highest scored problem involved tracing two recursive functions and analyzing their time complexity.
The document discusses the results of a midterm exam for a CS106B class. It provides statistics on exam scores including the median score of 54.0, mean of 52.1, and a breakdown of letter grades. It then discusses the solutions to 5 problems on the exam involving tracing recursive functions, vector and grid operations, dictionaries and maps, recursive string functions, and recursively trying arithmetic operators. The highest scored problem involved tracing two recursive functions and analyzing their time complexity.
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
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,
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. */
/* * 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. */
/* * 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); }