2026-01-08
By the end of this lab, you should be able to:
Upload solutions for the following activities to xSITe or Gradescope:
None of today’s activities will be graded, but they will serve as practice for future lab activities. Upload solutions to familiarize yourself with the submission process.
Note that the video and our textbook Cormen et al. (2022) adopt 1-based indexing. Here is the pseudocode for merge sort for 0-based indexing, as used by https://apps.michael-gastner.com/merge-sort/:

Merge sort is a divide-and-conquer algorithm because it breaks a problem into smaller, related subproblems and then combines these solutions to solve the original problem.
Divide-and-conquer algorithms are recursive. For instance, the sort procedure in the pseudocode on the previous slide calls itself in lines 6 and 7.
The example on the right illustrates the merge sort algorithm applied to a numeric array, modeled after Figure 2.4 in Cormen et al. (2022).
Italicized numbers indicate the sequence in which the sort() and merge() procedures are invoked, starting with the initial call to sort(a, 0, 7).
Download the image on the right from GitHub Pages in PNG or PDF format. Adopting the pattern from the example on the previous page, complete the following tasks:
sort() and merge() procedure calls.You may use any drawing tool, such as Annotely. When finished, upload the completed image (e.g., as a screenshot) to xSITe (Dropbox → Week 01 Lab Exercise 1: Merge Sort—Fill in the Gaps).
sort() and merge() procedures is identical to the previous example. This order depends only on the length of the array, not on its values.As with the insertion sort implementation discussed in the lecture, we split the merge sort implementation into multiple files to enhance code readability and maintainability. You can download the complete code as a ZIP archive.
main.cppimport_numbers_from_file.cpp and import_numbers_from_file.hmerge_sort.cpp and merge_sort.hmerge() and sort() procedures
makefilemake
main.cpp (Part 1)The first part of main.cpp includes the headers, defines exit codes, and validates command-line arguments:
#include <cstdlib>
#include <exception>
#include <iostream>
#include <string>
#include <vector>
#include "import_numbers_from_file.h"
#include "merge_sort.h"
int main(int argc, char *argv[]) {
enum ExitCode {
ok = EXIT_SUCCESS,
fail = 1,
usage = 2,
io = 3,
bad_input = 4,
};
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <filename>\n";
return usage;
}
main.cpp (Part 2)The second part reads numbers from a file, sorts them using merge sort, and prints the result:
try {
const std::string filename = argv[1];
std::vector<int> a = importNumbersFromFile(filename);
if (!a.empty()) {
mergeSort(a, 0, a.size() - 1);
}
for (std::size_t k = 0; k < a.size(); ++k) {
if (k > 0) {
std::cout << ", ";
}
std::cout << a[k];
}
std::cout << '\n';
return ok;
} catch (const std::runtime_error &ex) {
std::cerr << "Error: " << ex.what() << "\n";
return io;
} catch (const std::exception &ex) {
std::cerr << "Error: " << ex.what() << "\n";
return bad_input;
}
}merge_sort.cpp: The merge() Function (Part 1)The merge() function creates temporary arrays and copies elements:
#include "merge_sort.h"
#include <cstddef>
#include <vector>
static void merge(std::vector<int> &a, std::size_t l, std::size_t m,
std::size_t r) {
const std::size_t n_left = m - l + 1;
const std::size_t n_right = r - m;
std::vector<int> left(n_left);
std::vector<int> right(n_right);
for (std::size_t j = 0; j < n_left; ++j) {
left[j] = a[l + j];
}
for (std::size_t k = 0; k < n_right; ++k) {
right[k] = a[m + 1 + k];
}
std::size_t i = l;
std::size_t j = 0;
std::size_t k = 0;merge_sort.cpp: The merge() Function (Part 2)The function then merges the sorted subarrays back into the original array:
merge_sort.cpp: The mergeSort() FunctionThe mergeSort() function recursively divides the array and calls merge():
To prepare for future assignments, navigate to the Dropbox folder “Week 01 Lab Exercise 2a: Gradescope Demo—Merge Sort” on xSITe. Download the files as instructed in the assignment. Note that this is a practice assignment and will not be graded.
For simplicity, the solution file merge_sort.cpp is provided in the ZIP archive you downloaded earlier.
Upload the sample solution to Gradescope and review the autograder’s feedback. You can resubmit code as often as needed to familiarize yourself with the submission process. You may want to intentionally introduce an error to observe how the autograder responds.
Write a C++ program, consisting of a single file titled hello_world.cpp that prints “Hello, World!”—exactly these 13 characters, followed by a newline character—to the stdout console. Compile the code using makefile provided in the ZIP archive.
A template for hello_world.cpp is also provided in the ZIP archive. This template won’t print anything. Your task is to update the file.
Follow the instructions in the Dropbox folder “Week 01 Lab Exercise 2b: Gradescope Demo—Hello, World!” on xSITe to prepare your submission. Again, this is a practice assignment and will not be graded.
You might need to scroll down to view the entire code:
The lecture introduced insertion sort as the non-recursive algorithm shown below.
However, insertion sort can also be implemented as a recursive algorithm. To sort a[0..n], recursively sort the subarray a[0..(n-1)] and then insert a[n] into the sorted subarray. Write pseudocode for this recursive version. Submit your solution (e.g., a photo of your handwritten notes) to xSITe (Dropbox \(\rightarrow\) Pseudocode of Recursive Insertion Sort).


Implement insertion sort in C++ as a recursive function. Your implementation should be contained in a file named recursive_insertion_sort.cpp. A template file, together with other utilities for compilation are provided in this ZIP archive.
Upload your solution to Gradescope. Detailed instructions are provided on xSITe (Dropbox \(\rightarrow\) Week 01 Lab Exercise 3b: Gradescope—Recursive Insertion Sort in C++).
#include "recursive_insertion_sort.h"
#include <cstddef>
#include <vector>
// This function sorts the input vector of integers in ascending order in place
// using the insertion sort algorithm. It adopts a recursive approach (i.e.,
// it calls itself).
void recursiveInsertionSort(std::vector<int> &a, std::size_t n) {
// Base case: If the array has one or zero elements, it is already sorted
if (n <= 1) {
return;
}
// Insert a[n - 1] into the sorted subvector a[0:(n-2)]
recursiveInsertionSort(a, n - 1);
const int active_key = a[n - 1];
std::size_t h = n - 1;
while (h > 0 && a[h - 1] > active_key) {
a[h] = a[h - 1];
--h;
}
a[h] = active_key;
}We have studied three implementations for sorting an array of numbers:
Which algorithm is best in practice? The choice depends on the size of the input array and the relative efficiency of the algorithms, particularly in terms of running time and memory usage.
To evaluate their performance, we will compare the running times of the three algorithms for sorting arrays of various sizes. Using the std::chrono library, we can measure these running times with a high-resolution clock for precise time measurement.
Code for running-time measurements is available as a ZIP archive, containing the following files:
main.cppinsertion_sort.cpp and insertion_sort.hrecursive_insertion_sort.cpp and recursive_insertion_sort.hmerge_sort.cpp and merge_sort.hvega_lite_plot.cpp, vega_lite_plot.h, and nlohmann_json.hmakefileWhen you execute make run, the program generates arrays of random numbers and sorts them using non-recursive insertion sort, recursive insertion sort, and merge sort. The running times for arrays of different sizes are measured and stored in a JSON file. You can visualize the data by opening the generated file vega_lite_plot.html in a web browser. A sample run is shown on the following page.
Array Size Insertion Sort (µs) Recursive Insertion Sort (µs) Merge Sort (µs)
10 0 0 3
20 0 0 7
50 2 3 23
100 12 10 35
200 34 36 72
500 206 237 227
1000 1050 847 457
2000 3325 3421 893
On my computer, both versions of insertion sort exhibit approximately equal running times. Merge sort is slower on small arrays but faster on larger arrays. The representative plot on the following slide confirms this observation.
Next week, you will learn to analyze the running times of algorithms and express them using mathematical notation. The lecture and lab will cover sections of Chapters 3 and 4 in Cormen et al. (2022).
Week 01: Foundations (Lab)