Goal
This week’s lecture was about algorithms; this lab is about making them real. You write the two searches and count how many comparisons each one needs, so the O(n) versus O(log n) gap becomes a number on your screen. You write the two quadratic sorts and pick one from the command line, as in Lab 3. And you write two functions that call themselves. The notebook at the end measures the same algorithms in Python and draws the curves.
Steps
Accept Lab 4 and open it in Codespaces
⏱ 4 minClick Accept lab lab04 at the top of this page → Accept assignment → Open repository → green Code → Codespaces → Create codespace on main. When the terminal shows $:
$ python3 check.py:| search.c finds 50 at index 4: linear in 5 comparisons, binary in 3
...
0/12 checks passed | File | What it is |
|---|---|
search.c, sort.c, recursion.c | Parts A–C; the comment at the top of each file is the specification |
cs50.h, cs50.c, Makefile | the CS50 library and make search, make sort, make recursion |
lab04.ipynb | the timing notebook, not graded |
check.py, tests/ | the checks, one test file per part |
Part A · search.c (3 points)
⏱ 25 minRead a sorted list of numbers and a target, then search for the target with both algorithms and report the index and the number of comparisons:
$ make search$ ./searchHow many numbers? 7
Number: 1
Number: 5
Number: 10
Number: 20
Number: 50
Number: 100
Number: 500
Target: 50
Linear: found at index 4 after 5 comparisons
Binary: found at index 4 after 3 comparisons main is mostly written; you print the two result lines (or Linear: not found after 7 comparisons when the target is absent) and fill in the two functions. Both return the index or -1.
The one new thing is the counter. Each function receives int *comparisons, a pointer to the caller’s counter. You do not need to understand pointers yet (that is week 6); you need one idiom: (*comparisons)++; adds one to the counter the caller gave you. Put that line right before every if (numbers[...] == target) and the counts come out right.
For binary search keep two indices, low = 0 and high = n - 1, look at middle = (low + high) / 2, and move low or high past the middle depending on the comparison. The loop runs while low <= high. Trace the example by hand before you run it: 20, then 100, then 50; three comparisons.
Part B · sort.c (4 points)
⏱ 30 minSort a list of numbers with the algorithm named on the command line and print the result on one line:
$ make sort$ ./sort bubbleHow many numbers? 5
Number: 6
Number: 3
Number: 8
Number: 1
Number: 2
1 2 3 6 8 Three things to do, in order:
- Validate the argument exactly as in
caesar.c: one argument, equal toselectionorbubble(strcmp(argv[1], "bubble") == 0); otherwise printUsage: ./sort selection|bubbleandreturn 1. - Selection sort. For each position
ifrom 0 to n − 2, find the index of the smallest value fromito the end, then swap it into positioni. Aswapfunction that takes two pointers is already written for you; call it asswap(&numbers[i], &numbers[smallest]);. - Bubble sort. Up to n − 1 passes; in each pass compare every pair of neighbors and swap the ones in the wrong order. Keep a
bool swapped; if a whole pass swaps nothing,break.
Print with a space between numbers and no trailing space: printf("%i%s", numbers[i], i < n - 1 ? " " : "\n"); is one way. The tests try duplicates, negative numbers, a single number and a hundred random ones.
Part C · recursion.c (3 points)
⏱ 20 minTwo functions that call themselves:
$ make recursion$ ./recursionHeight: 3
#
##
###
n: 5
5! = 120 draw(n) prints a left-aligned pyramid exactly like the lecture’s recursion.c: if n <= 0 return; otherwise draw(n - 1) first, then one row of n hashes. factorial(n) returns n × (n − 1) × … × 1: the base case is factorial(0) = 1 (and 1 for n = 1), the recursive case is n * factorial(n - 1). Use long, because 20! does not fit in an int; print it with %li. In main, re-prompt while the height or n is outside 0–20.
The checks also read your source: factorial must contain no for or while, and both functions must call themselves. Recursion is the point of this part, not an optional style.
Submit
⏱ 2 min$ git add -A$ git commit -m "Lab 4"$ git push Your score appears under Releases about two minutes later. Push as often as you like before Friday, October 23, 23:59; the last push before the deadline counts, and late pushes lose 10% per day for up to five days.
How to submit
Points: search 3, sort 4, recursion 3. The other ways to work and to submit from the browser are the same as in Lab 2; cs50.h and cs50.c travel with your .c files.
Explore: measure the algorithms
lab04.ipynb is not graded. It counts the steps of linear versus binary search for a billion items, times selection, bubble and merge sort on growing random lists and plots the curves, and prints the call tree of the recursive draw. Open it in Colab; nothing to install. The shapes you see there are what Big O describes.
Lab 4 · Explore: measure the algorithms
Read it here, or open it in Colab: it writes, compiles and runs C right in the browser.
Challenges (optional, not graded)
- Merge sort in C. Add
mergeas a third option tosort.c, followingmerge.cfrom the week page. Time all three on 10 000 numbers withtime ./sort merge < input.txt. - Recursive binary search. Rewrite
binary_searchwithout a loop: a function that calls itself on the left or right half. - Count the swaps. Add a swap counter to both sorts and compare them on the same input. Which one swaps less, and why?