Developing Algorithms: Pseudocode, MOD, and Building Blocks
An algorithm is a finite set of instructions that accomplishes one specific task, and you can write the same algorithm in plain English, draw it as a flowchart, or type it as code. The recipe card for pancakes, the steps your phone follows to sort your photos by date, and the rules a referee uses to decide a tie are all algorithms.
What counts as an algorithm?
Two words in the definition matter. Finite means the steps run out: an algorithm always comes to an end. Specific task means it has a clear job, like "find the highest score" or "decide if this year is a leap year".
Here is an algorithm written in natural language, which means everyday words:
The same steps can be drawn as a diagram. In a flowchart, ovals mark the start and end, rectangles are actions, and diamonds are yes-or-no questions:
( Start )
|
[ total ← 0 ]
|
< Any scores left? > -- no --> [ DISPLAY(total) ] --> ( End )
| yes
[ total ← total + next score ]
|
( back up to "Any scores left?" )It can also be written as pseudocode, a halfway point between English and a programming language. The exam uses its own pseudocode, printed on a reference sheet you get during the test:
total ← 0FOR EACH score IN scores{total ← total + score}DISPLAY(total)
Natural language, diagrams and pseudocode are for people. For a computer to carry out an algorithm, someone implements it in a programming language. That language can be text-based, like Python, or visual, like the drag-and-drop blocks in Scratch. The exam shows its pseudocode in both a text form and a block form.
Look back at the flowchart and you can spot three ideas. Steps that follow one after another are sequencing. The diamond that picks a path is selection. The arrow that loops back is iteration. Every algorithm, from a calculator app to a game's enemy movement, can be built from combinations of these three.
Why does the order of the steps matter?
Sequencing means each step is carried out in the order the statements are written, top to bottom. A code statement is one part of a program that tells the computer to do an action, like score ← score + 10 or DISPLAY(score).
Order can change the answer completely. Suppose you want two variables to trade values. This pseudocode looks reasonable but fails:
a ← "cereal"b ← "toast"a ← bb ← a
After line 3, a holds "toast" and the word "cereal" is gone for good. Line 4 then copies "toast" back into b. The fix is to save one value in a third variable before anything is overwritten. Run both versions:
Wrong swap: toast toast Right swap: toast cereal
Clear writing matters too. Meaningful names like temp and total, one action per line, and steps in a sensible order make an algorithm readable for your teammates, your teacher, and you next month.
How does a computer work out an expression?
An expression is anything that produces a value. It can be a single value like 7, a variable like score, values joined by operators like score + 7, or a call to a procedure that returns a value, like LENGTH(names). However long it is, an expression is evaluated down to one single value.
The arithmetic operators on the reference sheet are +, -, *, / and MOD. Division keeps the decimal part, so 9 / 4 is 2.25, the same as in Python.
a MOD b gives the remainder when a is divided by b. For example, 23 MOD 4 is 3, because 4 goes into 23 five times (that makes 20) with 3 left over. The exam only uses MOD with a a whole number of 0 or more and b a whole number greater than 0. In Python, MOD is written %.
Expressions follow an order of operations, set by each programming language. In the exam pseudocode it is the order you know from math class: parentheses first, then *, / and MOD (all at the same level, worked left to right), then + and - (also left to right). So 2 + 14 MOD 4 * 3 is worked out like this:
14 MOD 4 is 2 (MOD and * are at the same level, and MOD comes first reading left to right).2 * 3 is 6.2 + 6 is 8.Python's % sits at the same level as * and /, so Python gets 8 too:
2.25 3 8 0 10: even? True, multiple of 5? True, last digit 0 15: even? False, multiple of 5? True, last digit 5 21: even? False, multiple of 5? False, last digit 1 30: even? True, multiple of 5? True, last digit 0
Those last lines show why MOD is so useful. n MOD 2 = 0 tests for even numbers, n MOD d = 0 tests whether n divides evenly by d, and n MOD 10 pulls out the last digit. MOD also makes values wrap around, like the days of the week or a 24-hour clock:
2 days after Fri is Sun 3 days after Fri is Mon 10 days after Fri is Mon 2 hours after 09:00 is 11:00 5 hours after 09:00 is 14:00 20 hours after 09:00 is 05:00
Can two different algorithms do the same job?
Yes. Algorithms can be written in different ways and still accomplish the same task, and completely different algorithms can solve the same problem.
A common case is a conditional that sets a true-or-false variable. Some conditional statements can be rewritten as one Boolean expression. A cinema gives a discount to children under 13 and to people 65 or older:
IF(age < 13){discount ← true}ELSE{IF(age ≥ 65){discount ← true}ELSE{discount ← false}}
The whole thing does the same as one line: discount ← (age < 13) OR (age ≥ 65). It works the other way too: a Boolean expression such as canVote ← (age ≥ 18) AND registered can be rewritten as nested IF statements that set canVote to true only when both parts hold.
How can you be sure two versions really agree? Try every input that matters and compare:
Ages checked: 0 to 120 Ages where the versions disagree: []
The same idea applies to whole algorithms. To find the highest score you could keep the biggest value seen so far, or you could sort the scores and take the last one. Both are correct:
Keep the biggest: 95 Sort, then take the last: 95
The reverse warning matters on the exam too: algorithms that look similar can give different results. Here are two ways to label a temperature. The only difference is an else:
15°C two ifs: cold if-else: cold 25°C two ifs: warm if-else: warm 35°C two ifs: warm if-else: hot
At 35°C, the first version sets "hot" and then the second IF also runs, because 35 is greater than 20, so "hot" is replaced by "warm". With else (Python's elif is an ELSE with an IF inside it), only one branch can run. When you compare two code segments on the exam, test a value that makes more than one condition true.
How do you build a new algorithm from old ones?
New algorithms come from three places: a fresh idea, combining algorithms you already have, or modifying one that almost does the job. Knowing a few classic algorithms by heart makes the last two much easier. These come up again and again:
Here is the maximum algorithm in exam pseudocode. It starts with the first element, not with 0, so it also works when every number is negative:
PROCEDURE findMax(numbers){biggest ← numbers[1]FOR EACH n IN numbers{IF(n > biggest){biggest ← n}}RETURN(biggest)}
Now combine. A school raffle gives a prize to every ticket number divisible by 3, and the organizers want the largest winning number and the average of the winning numbers. Each piece below is a small, tested procedure, and the new algorithm is a few lines of glue:
Winning tickets: [27, 33, 51, 75] Largest: 75 Average: 46.5
Building on correct algorithms pays off in three ways. Development is faster, because you are not rewriting what already works. There is less to test, because the pieces were tested before. And errors are easier to find: if the raffle report is wrong, the bug is most likely in the new glue code, not in find_max.
Check your understanding
What is displayed when this code segment runs?
result ← 4 + 18 MOD 5 * 2DISPLAY(result)
What is displayed when this code segment runs?
a ← 3b ← 8a ← bb ← aDISPLAY(a)DISPLAY(b)
Which of the following statements assign the same value to winner as the code segment, for every possible value of points and lives? Select two answers.
Select 2 answers.
IF(points ≥ 50){IF(lives > 0){winner ← true}ELSE{winner ← false}}ELSE{winner ← false}
The two code segments look alike. For which starting value of n do they display different values?
Segment IIF(n MOD 2 = 0){n ← n / 2}IF(n MOD 2 = 1){n ← 3 * n + 1}DISPLAY(n)Segment IIIF(n MOD 2 = 0){n ← n / 2}ELSE{n ← 3 * n + 1}DISPLAY(n)
A student creates a new algorithm by combining two procedures that the class wrote and tested earlier. Which of the following are benefits of this approach? Select two answers.
Select 2 answers.
What is displayed when this code segment runs?
total ← 0n ← 1REPEAT 6 TIMES{IF(n MOD 3 = 0){total ← total + n}n ← n + 1}DISPLAY(total)
Which of the following is NOT an expression?
Practice exercises
This function should return the average of three test scores, but it gives wrong answers: average_of_three(80, 90, 100) returns about 203.3 instead of 90.0.
Find the order-of-operations bug and fix it.
A year is a leap year when it is divisible by 4. Years divisible by 100 are the exception: they are not leap years, unless they are also divisible by 400.
Write is_leap_year(year) that returns True or False. Combine divisibility checks (with %) and Boolean operators.
is_leap_year(2024) -> True
is_leap_year(1900) -> FalseWrite max_multiple(numbers, divisor) that returns the largest number in the list that is evenly divisible by divisor. If no number in the list is divisible, return None.
Build it from two algorithms you know: the divisibility check and finding a maximum.
max_multiple([4, 9, 12, 7], 3) -> 12
max_multiple([5, 11, 13], 2) -> NoneExam topics: 3.3 Mathematical Expressions (AAP-2.A, AAP-2.B, AAP-2.C), 3.9 Developing Algorithms (AAP-2.L, AAP-2.M)