Exam practice
Every question from the end of every unit, with hints and answers to open. After you check an answer, mark how you did, and come back to the ones you didn’t get.
12 questions
Unit 4 · Algorithms and Efficiency
What three things do programmers look at when they compare two algorithms for the same job? Explain each in one sentence, with an example.
Answer
- Correctness: does it give the right answer for every input, including edge cases? Example: a binary search must find the first and last items and say when an item isn’t there; test cases check it.
- Efficiency: how much work does it do, in steps and memory, especially as the data grows? Example: merge sort makes about 9,000 comparisons for 1,000 items, bubble sort about 500,000.
- Clarity: how easy is it to read, check and change? Example: a loop that adds 1 to n is obvious; the formula n(n + 1) ÷ 2 is shorter but needs a comment saying why it is right.
Copy and complete the table, for an algorithm of each kind that takes 100 steps for 1,000 items. (Assume the steps follow the kind of growth exactly.)
| Kind | 1,000 items | 2,000 items | 4,000 items |
|---|---|---|---|
| constant | 100 | ||
| linear | 100 | ||
| quadratic | 100 |
Answer
| Kind | 1,000 items | 2,000 items | 4,000 items |
|---|---|---|---|
| constant | 100 | 100 | 100 |
| linear | 100 | 200 | 400 |
| quadratic | 100 | 400 | 1,600 |
Constant work doesn’t change; linear doubles with each doubling; quadratic becomes 4 times as much (2 × 2), so 4,000 items take 16 times the work of 1,000.
Thirty teams play in a league where every team plays every other team once. How many matches are there? How many if the league grows to 60 teams? What kind of growth is this?
Answer
Each match is a pair of teams: 30 × 29 ÷ 2 = 435 matches. With 60 teams: 60 × 59 ÷ 2 = 1,770 matches, about 4 times as many (1,770 ÷ 435 ≈ 4.07). Doubling the teams about quadruples the matches: quadratic growth, O(n²).
Merge the sorted lists 12, 30, 45, 66 and 8, 31, 50. Show each comparison, and count them.
Answer
| Compare | Smaller goes next | Merged so far |
|---|---|---|
| 12 and 8 | 8 | 8 |
| 12 and 31 | 12 | 8, 12 |
| 30 and 31 | 30 | 8, 12, 30 |
| 45 and 31 | 31 | 8, 12, 30, 31 |
| 45 and 50 | 45 | 8, 12, 30, 31, 45 |
| 66 and 50 | 50 | 8, 12, 30, 31, 45, 50 |
| (the second list is empty) | the rest: 66 | 8, 12, 30, 31, 45, 50, 66 |
6 comparisons for 7 numbers (the most possible, 7 − 1).
Sort 47, 12, 90, 33, 68, 5, 21, 74 with merge sort. Show the piles after each round, and count the comparisons in each round.
Answer
- Start: [47] [12] [90] [33] [68] [5] [21] [74]: 8 piles of one.
- Round 1 (4 merges of 1 + 1): [12, 47] [33, 90] [5, 68] [21, 74]: 4 comparisons.
- Round 2: [12, 47] with [33, 90]: 12/33 → 12, 47/33 → 33, 47/90 → 47, then 90: 3 comparisons → [12, 33, 47, 90]. [5, 68] with [21, 74]: 5/21 → 5, 68/21 → 21, 68/74 → 68, then 74: 3 comparisons → [5, 21, 68, 74]. 6 comparisons.
- Round 3: [12, 33, 47, 90] with [5, 21, 68, 74]: 12/5 → 5, 12/21 → 12, 33/21 → 21, 33/68 → 33, 47/68 → 47, 90/68 → 68, 90/74 → 74, then 90: 7 comparisons → [5, 12, 21, 33, 47, 68, 74, 90].
In all, 4 + 6 + 7 = 17 comparisons in 3 rounds.
Write an algorithm, as numbered steps from Start to Stop, to find whether a list of n numbers is in order from smallest to biggest. How many comparisons does it make at most? What kind of growth is that?
Answer
Algorithm
Step 1: StartStep 2: Read the list of n numbersStep 3: Set i = 1Step 4: Is i < n? Yes: go to Step 5 No: Display "in order", go to Step 7Step 5: Is number i > number i + 1? Yes: Display "not in order", go to Step 7 No: go to Step 6Step 6: Set i = i + 1, go to Step 4Step 7: StopIt compares each pair of neighbors once, so at most n − 1 comparisons (when the list is in order, or only the last pair is wrong). That is linear growth, O(n). (Here the numbers are counted from 1, as in everyday speech; in Python they would be positions 0 to n − 1.)
Explain the difference between a deterministic and a random algorithm. Give an example of each, and say one advantage of the random one.
Answer
A deterministic algorithm does the same steps and gives the same output every time it gets the same input. Example: binary search, or merge sort.
A random algorithm makes some of its choices by chance (random numbers), so its steps, and sometimes its answer, can differ from run to run on the same input. Example: quicksort with a random pivot, or estimating π by dropping random dots.
One advantage (either is enough): it can give a good answer quickly where an exact one would take far too long (Monte Carlo); or no particular input can make it slow every time (random quicksort, which is fast on average for every list, even one already sorted).
Raju’s program checks whether any two of the 1,500 students in his school share a birthday. It compares every pair of students. How many comparisons does it make at most? Suggest a faster plan, and say how many steps it needs.
Answer
Every pair: 1,500 × 1,499 ÷ 2 = 1,124,250 comparisons at most (quadratic).
Faster: go through the students once, keeping each birthday seen in a dictionary (the birthday as the key). For each student, if their birthday is already a key, two students share it; otherwise add it. That is at most 1,500 dictionary looks, linear. (With only 366 possible birthdays, a shared one is in fact certain long before the end: a dictionary can hold at most 366 different birthdays, so the 367th student must share one.)
A program that uses an O(n²) algorithm takes 3 seconds for 10,000 records. About how long will it take for 30,000 records? And if it used an O(n) algorithm that also took 3 seconds for 10,000?
Answer
30,000 is 3 times 10,000. Quadratic: 3 × 3 = 9 times the work, so about 27 seconds. Linear: 3 times the work, about 9 seconds.
Read the program and answer. a. What does it print? b. What does the function do, and what kind of growth is it? c. Rewrite it so that it is linear.
def count_matches(a, b): count = 0 for x in a: for y in b: if x == y: count = count + 1 return count print(count_matches(["tea", "momo", "chiya"], ["momo", "tea", "lassi", "sel roti"]))Answer
- a.It prints
2:"tea"and"momo"are in both lists. - b.It counts how many items of
aare also inb(each item ofaagainst each ofb). The inner loop runs len(b) times for each item ofa: about len(a) × len(b) comparisons, quadratic when both lists are about the same length. - c.Put the items of
binto a dictionary first, then look up each item ofa:
def count_matches(a, b): in_b = {} for y in b: in_b[y] = True count = 0 for x in a: if x in in_b: count = count + 1 return count print(count_matches(["tea", "momo", "chiya"], ["momo", "tea", "lassi", "sel roti"]))Output
2Now each list is gone through once, and each look-up is constant time: about len(a) + len(b) steps, linear. (One difference: if b held "tea" twice, the first version would count it twice; the dictionary keeps it once. Say which you want before you choose.)
Why does an exponential algorithm become useless so quickly, however fast the computer? Explain with numbers.
Answer
An exponential algorithm’s work doubles each time one item is added: 2ⁿ steps for n items. At a billion steps a second, 30 items (about a billion steps) take about a second; 40 items take about 18 minutes; 50 items about 13 days; 60 items about 37 years; 100 items far longer than the age of the universe. A computer 1,000 times faster only adds about 10 items (2¹⁰ = 1,024) to what can be done in the same time. Faster computers barely help; only a better algorithm, if one exists, does.
A student times two sorts once each, with a 200-item list for sort P and a 2,000-item list for sort Q, one on her phone and one on the school computer, and says P is faster. Give three reasons why her test isn’t fair, and say how to do it properly.
Answer
- The lists are different sizes: Q did more work because it had 10 times as many items.
- The devices are different: a phone and a computer run at different speeds, so the times say more about the devices than the sorts.
- Each was timed only once: other apps, and a slow first run, can change a single time a lot.
(Also: the lists could be in different orders; a nearly sorted list is easy for some sorts.)
Properly: give both sorts copies of the same lists, on the same computer, time each several times and take the middle time, and repeat for growing sizes (say 500, 1,000, 2,000, 4,000) to see how each one’s time grows.
