Extra Practice Problems (Pre-Midterm)


This page is curated by Yasmine Alonso, Tommy DeBenedetti, and Sean Szumlanski, drawing upon materials from previous quarters.

These problems will give you more practice with concepts covered on the midterm exam.

⚠️ This page is actively maintained. Check back each week for additional problems.

🌱 For your convenience, new problem categories are marked with a sprout emoji each week.

📝 C++ and ADT exercises were added Sunday, April 12.

🌱 Programming in C++

1. countNumbers (count.cpp)

Topics: Vectors, strings, file reading, while true, conditional statements, Stanford C+++ library

The function countNumbers reads a text file and prints the number of times a user entered number appears in that text file. A user can continually enter numbers until they hit "Enter" or "Return" on their keyboard. Here are some library functions that will be useful for this task:

  • readLines, to read all lines from a file stream into a Vector
  • stringSplit, to divide a string into tokens
  • getLine, to read a line of text entered by the user
  • stringIsInteger, to confirm a string of digits is valid integer

In particular you will be asked to write the following function

void countNumbers(string filename)

When given the following file, named numbers.txt, as input, your function should print 1 when a user enters 42. Similarly, when the user enters another number like 9, your function should print 2. Finally, the function ends when the user presses "Return".

42 is the Answer to the Ultimate Question of Life, the Universe, and Everything
This is a negative number: -9
Welcome to CS106B!
I want to own 9 cats and 9 dogs.
/*
 * Function: countNumbers
 * ----------------------
 * Write a program to read through a given file and count the
 * the number of times a user inputed number appears in that file. You  
 * can assume that numbers will be composed entirely of numerical digits, 
 * optionally preceded by a single negative sign.
 */
void countNumbers(string filepath) {
    ifstream in;
    if (!openFile(in, filepath)) {
        return;
    }

    Vector<string> lines = readLines(in);

    while (true) {
        string number = getLine("Enter a number to check (enter to quit): ");
        if (number == "") {
            break;
        }
        if (!stringIsInteger(number)) {
            cout << "Please enter a number" <<endl;
            continue;
        }
        int count = 0;
        for (string line : lines) {
            Vector<string> tokens = stringSplit(line, " ");
            for (string t : tokens) {
                if (t == number) {
                    count ++;
                }
            }
        }
        cout << "Number " << number << " appeared " << count << " times in the file." << endl;
    }
}

2. ASCII Count 'em

Topics: ASCII, strings

Write a function that takes a string as its only argument and returns a count of how many characters in that string fall between 'e' and 'm' (inclusive). In writing this function, the only comparisons you can make are to 'e' and 'm' (i.e., you cannot compare each character to 'f', 'g', 'h', 'i', and so on), and you cannot hard-code any numeric ASCII values (i.e., you cannot hard-code the integers 101 or 109 in your function – which are the ASCII values for 'e' and 'm' respectively – or any other integer values nearby).

The function signature is as follows:

int countEM(string str)

For example, countEM("sponges") should return 2; the only characters in sponges that fall between 'e' and 'm' (inclusive) are 'g' and 'e'. Similarly, countEM("grunge") should return 3; only the characters 'g' (which occurs twice) and 'e' (which occurs once) are in range.

int countEM(string str) {
    int count = 0;
    for (char ch : str) {
        if (ch >= 'e' && ch <= 'm') {
            count++;
        }
    }
    return count;
}

🌱 ADTs

1. Mirror

Topic: Grids

Write a function mirror that accepts a reference to a Grid of integers as a parameter and flips the grid along its diagonal. You may assume the grid is square; in other words, that it has the same number of rows as columns. For example, the grid below that comes first would be altered to give it the new grid state shown afterwards:

Original state: 
{ { 6, 1, 9, 4},                
  {-2, 5, 8, 12},                  
  {14, 39, -6, 18},             
  {21, 55, 73, -3} }               

Mirrored state: 
 { {6, -2, 14, 21},
   {1, 5, 39, 55},
   {9, 8, -6, 73},
   {4, 12, 18, -3} }

Bonus: How would you solve this problem if the grid were not square?

// solution
void mirror(Grid<int>& grid) {
    for (int r = 0;r < grid.numRows(); r++) {
        // start at r+1 rather than 0 to avoid double-swapping 
        for (int c = r + 1; c < grid.numCols(); c++) { 
            int temp = grid[r][c]; 
            grid[r][c] = grid[c][r]; 
            grid[c][r] = temp;
        } 
    }
}
// bonus 
void mirror(Grid<int>& grid) {
    Grid<int> result(grid.numCols(), grid.numRows());
    for (int r = 0; r < grid.numRows(); r++) {
        for (int c = 0; c < grid.numCols(); c++) {
            result[r][c] = grid[c][r];
        }
    }
    grid = result;
}

2. Collection Mystery

Topics: Stacks, queues

void collectionMystery(Stack<int>& s) 
{ 
    Queue<int> q;
    Stack<int> s2;

    while (!s.isEmpty()) {
       if (s.peek() % 2 == 0) {
            q.enqueue(s.pop()); 
        } else {
            s2.push(s.pop());
        }
    }
    while (!q.isEmpty()) {
        s.push(q.dequeue()); 
    }
    while(!s2.isEmpty()) { 
        s.push(s2.pop());
    }
    cout<< s << endl;
}

Write the output produced by the above function when passed each of the following stacks. Note that stacks and queues are written in ​front to back order, with the oldest element on the left side of the queue/stack.

Stacks:

{1, 2, 3, 4, 5, 6}                ________________________________________
{42, 3, 12, 15, 9, 71, 88}        ________________________________________
{65, 30, 10, 20, 45, 55, 6, 1}    ________________________________________

{6, 4, 2, 1, 3, 5}
{88, 12, 42, 3, 15, 9, 71}
{6, 20, 10, 30, 65, 45, 55, 1}

3. Reversing a Map

Topic: Nested data structures

Write a function

Map<int, Set<string>> reverseMap(Map<string, int>& map)

that, given a Map<string, int> that associates string values with integers, produces a Map<int, Set<string>> that’s essentially the reverse mapping, associating each integer value with the set of strings that map to it. (This is an old job interview question from 2010.)

Here’s one possible implementation.

Map<int, Set<string>> reverseMap(Map<string, int>& map) {
    Map<int, Set<string>> result;
    for (string oldKey : map) {
        // Note: we check containsKey here but this isn't 
        // necessary since Maps auto-initialize values 
        // on square bracket access if the key is not 
        // present
        if (!result.containsKey(map[oldKey])) {
            result[map[oldKey]] = {};
        }
        result[map[oldKey]].add(oldKey);
    }
    return result;
}

4. Stack vs Vector showdown

Topics: Stacks, vectors

We will analyze a simple program that emulates a text editor. The program accepts input from a user which can be of two forms:

  • ADD string: This adds a one word string into the text editor

  • UNDO: This removes the most recently added string from the editor.

When the user finishes providing input (by hitting ENTER), we print a string which represents the words in the text editor, in the order they were added.

Example: If we receive user input like "ADD I", "ADD Love", "ADD 106A", "UNDO", "ADD 106B", the program prints out "I love 106B".

int main() {
    Stack<string> words;

    while (true) {
        string command = getLine("Enter a command (press enter to quit): ");
        if (command == "") {
            break;
        }

        Vector<string> splitCommands = stringSplit(command, " ");
        if (splitCommands[0] == "ADD") {
            words.push(splitCommands[1]);
        } else if (splitCommands[0] == "UNDO") {
            words.pop();
        }
    }

    string result;
    while (!words.isEmpty()) {
        result = words.pop() + result;
    }
    cout << result << endl;
    return 0;
}

First, trace through this program on the example input provided above and see if you can discern how it's working. If necessary, refer to the Stanford C++ Library docs to see what functions like getLine() and stringSplit are doing.

Next, run the program, entering the provided inputs, and observe its output. Does the output match your expectation from having read the code? If not, use the debugger to step through the program and see where its behavior deviates from what you expected. After that, try different outputs and ensure the output is what you'd expect.

Finally, see if you can take at least an hour-long break from the problem and then try to code up a program that does the same thing without referring back to the code on this page and without having attempted to completely memorize the initial solution the first time around.

5. Maps

Topic: Maps

Here, we analyze a simple program that uses maps to count elements in a vector:

Map<string, int> countElements(Vector<string>& names) {
    Map<string, int> frequency;
    for (string name: names) {
        // When using the square bracket syntax([]), we don't need to initialize
        // names in the map before adding unto it. If name doesn't already exist
        // in the map, [] in the Stanford Map will initialize it for us.
        frequency[name] += 1;
    }
    return frequency;
}

What will this function return if you pass it a vector of strings (some of which are repeated)? Verify that it behaves as expected by creating a new program that calls this function and then prints out the map that it returns. Check that you're understanding how this program is working and that you understand where the resulting map's key/value pairs are coming from.