Skip to the page
Year 10 Β· Computer Science Β· Spring 2 Β· Algorithm design and problem solving

Searching and sorting; validation and verification

What this lesson covers

7.4 Standard methods of solution

Cambridge IGCSE Computer Science 0478 Β· Topic 7: Algorithm design and problem-solving Β· Paper 2

7.5 Validation and verification

Cambridge IGCSE Computer Science 0478 Β· Topic 7: Algorithm design and problem-solving Β· Paper 2

7.6 Test data

Cambridge IGCSE Computer Science 0478 Β· Topic 7: Algorithm design and problem-solving Β· Paper 2

You will learn to

  • Write and trace a linear search and a bubble sort in pseudocode.
  • Explain the difference between validation and verification.
  • Describe range, length, type, presence, format and check digit checks, and write a validation loop.
  • Choose normal, abnormal, extreme and boundary test data for a range check.

Success criteria

  • I can trace one full pass of a bubble sort on five numbers.
  • I can name the check that stops an age of 150, and write it in pseudocode.
  • I can explain why a double entry check is verification, not validation.
  • I can give test data of each type for a range check of 1 to 100.
The syllabus points for these sections
  • Write totalling and counting in pseudocode and Python.
  • Find the maximum, minimum and average of a set of values.
  • Write and trace a linear search.
  • Write and trace a bubble sort.
  • Count the comparisons a bubble sort makes.
  • Explain the difference between validation and verification.
  • Describe and write range, length, type, presence, format and check digit checks.
  • Describe visual checks and double entry checks.
  • Write a validation loop that repeats until the input is acceptable.
  • Define normal, abnormal, extreme and boundary data.
  • Choose test data for a given range and give the expected result.
  • Explain why each type of test data is needed.

Key words

Say each word, then read what it means. Every one is in the glossary too.

Program development life cycle
The four stages of making a program: analysis, design, coding and testing.
Pseudocode
A structured, code-like way of writing an algorithm that is not tied to one language.
Totalling
Adding values into a running total, for example Total ← Total + Value.
Counting
Adding 1 to a counter each time something happens.
Linear search
Checking each item in a list in turn until the target is found or the list ends.
Bubble sort
Sorting by comparing neighbouring items and swapping them if they are in the wrong order, pass after pass.
Validation
An automatic check that input data is reasonable and follows set rules.
Verification
A check that data has been copied or typed in exactly as the original.
Check digit
An extra digit calculated from the other digits, used to catch typing errors.
Normal data
Test data that should be accepted.
Abnormal data
Test data that should be rejected.
Extreme data
The largest and smallest values that should be accepted.
Boundary data
The largest and smallest accepted values and the nearest rejected values next to them.
Trace table
A table used in a dry run to record the value of each variable as an algorithm runs.

The explanation

Read it here, or open the study page below to go one step at a time with things to try.

7.4 Standard methods of solution

Totalling and counting

Totalling means adding values into a running total: `Total ← Total + Value`.

Counting means adding 1 each time something happens: `Count ← Count + 1`.

Both variables must start at 0 before the loop.

e.g.Example
Marks 34, 48, 21, 40, 15, 45. Pass mark 25. Total: 0 β†’ 34 β†’ 82 β†’ 103 β†’ 143 β†’ 158 β†’ 203 PassCount: 34 yes (1), 48 yes (2), 21 no, 40 yes (3), 15 no, 45 yes (4) Output: Total: 203, Number of passes: 4
DECLARE Marks : ARRAY[1:6] OF INTEGER
DECLARE Index : INTEGER
DECLARE Total : INTEGER
DECLARE PassCount : INTEGER
// Marks already holds 34, 48, 21, 40, 15, 45
Total ← 0
PassCount ← 0
FOR Index ← 1 TO 6
  Total ← Total + Marks[Index]
  IF Marks[Index] >= 25
    THEN
      PassCount ← PassCount + 1
  ENDIF
NEXT Index
OUTPUT "Total: ", Total
OUTPUT "Number of passes: ", PassCount
marks = [34, 48, 21, 40, 15, 45]
total = 0
pass_count = 0
for index in range(6):
    total = total + marks[index]
    if marks[index] >= 25:
        pass_count = pass_count + 1
print("Total:", total)
print("Number of passes:", pass_count)
!Watch out

Setting Total to 0 inside the loop is a classic error. The total is wiped each time round, so only the last value is kept.

Finding the maximum and minimum

To find the maximum (largest), keep a variable `Highest`. Compare each value with it. If the value is bigger, it becomes the new `Highest`.

The minimum (smallest) works the same way with `Lowest` and `<`.

Start `Highest` at the smallest possible value and `Lowest` at the largest possible value. Another safe way is to start both at the first item.

e.g.Example
Marks out of 50: 34, 48, 21, 40, 15, 45. Highest: 0 β†’ 34 β†’ 48 (21, 40, 15, 45 are not bigger than 48) Lowest: 50 β†’ 34 β†’ 21 β†’ 15 (40, 45 are not smaller than 15) Output: Highest: 48, Lowest: 15
DECLARE Marks : ARRAY[1:6] OF INTEGER
DECLARE Index : INTEGER
DECLARE Highest : INTEGER
DECLARE Lowest : INTEGER
// Marks already holds 34, 48, 21, 40, 15, 45 (each out of 50)
Highest ← 0
Lowest ← 50
FOR Index ← 1 TO 6
  IF Marks[Index] > Highest
    THEN
      Highest ← Marks[Index]
  ENDIF
  IF Marks[Index] < Lowest
    THEN
      Lowest ← Marks[Index]
  ENDIF
NEXT Index
OUTPUT "Highest: ", Highest
OUTPUT "Lowest: ", Lowest
marks = [34, 48, 21, 40, 15, 45]
highest = 0
lowest = 50
for index in range(6):
    if marks[index] > highest:
        highest = marks[index]
    if marks[index] < lowest:
        lowest = marks[index]
print("Highest:", highest)
print("Lowest:", lowest)
!Watch out

If Lowest starts at 0, no mark is ever smaller, so the answer is wrong. Start Lowest at the top of the range (50 here) or at the first value.

Finding the average

The average (mean) is the total divided by how many values there are.

First total the values in a loop. Then divide once, after the loop.

The answer is usually not a whole number, so store it as `REAL`. Use `ROUND` to give a set number of decimal places.

e.g.Example
Marks 34, 48, 21, 40, 15, 45. Total = 203. Count = 6. Average = 203 Γ· 6 = 33.8333… Rounded to 2 decimal places: 33.83
DECLARE Marks : ARRAY[1:6] OF INTEGER
DECLARE Index : INTEGER
DECLARE Total : INTEGER
DECLARE Average : REAL
// Marks already holds 34, 48, 21, 40, 15, 45
Total ← 0
FOR Index ← 1 TO 6
  Total ← Total + Marks[Index]
NEXT Index
Average ← Total / 6
OUTPUT "Average: ", ROUND(Average, 2)
marks = [34, 48, 21, 40, 15, 45]
total = 0
for index in range(6):
    total = total + marks[index]
average = total / 6
print("Average:", round(average, 2))
!Watch out

Do not divide inside the loop. Also check the count is not 0 before dividing, or the program crashes.

Linear search

A linear search looks for a value by checking each item in a list, one at a time, from the start.

It stops when it finds the item, or when it reaches the end of the list.

Try it: the toy's list holds numbers, not names. Type 22 (the last item), press Search for it, then Run all. Then try 99, which is not there. Count the comparisons each time.

e.g.Example
List: Lucia, Hugo, Martina, Pablo, Sofia, Leo. Target: Pablo. Position 1: Lucia β‰  Pablo Position 2: Hugo β‰  Pablo Position 3: Martina β‰  Pablo Position 4: Pablo = Pablo β†’ Found ← TRUE Output: Pablo found at position 4 (4 comparisons) Target Ana: all 6 compared, none match β†’ Ana is not in the list
DECLARE Names : ARRAY[1:6] OF STRING
DECLARE Target : STRING
DECLARE Index : INTEGER
DECLARE Found : BOOLEAN
// Names already holds Lucia, Hugo, Martina, Pablo, Sofia, Leo
OUTPUT "Which name do you want to find? "
INPUT Target
Found ← FALSE
Index ← 1
WHILE Found = FALSE AND Index <= 6 DO
  IF Names[Index] = Target
    THEN
      Found ← TRUE
    ELSE
      Index ← Index + 1
  ENDIF
ENDWHILE
IF Found = TRUE
  THEN
    OUTPUT Target, " found at position ", Index
  ELSE
    OUTPUT Target, " is not in the list"
ENDIF
names = ["Lucia", "Hugo", "Martina", "Pablo", "Sofia", "Leo"]
target = input("Which name do you want to find? ")
found = False
index = 0
while found == False and index < 6:
    if names[index] == target:
        found = True
    else:
        index = index + 1
if found == True:
    print(target, "found at position", index + 1)
else:
    print(target, "is not in the list")
?Why?

A linear search works on any list, sorted or not. The cost is time: a list of 1000 names can need 1000 comparisons.

!Watch out

The `Found` flag stops the loop early. Without it the search carries on to the end even after the name is found.

There is something to try for this step in the IGCSE library.

Bubble sort

A bubble sort puts a list in order. It compares each pair of neighbours. If they are in the wrong order, it swaps them.

One trip through the list is a pass. After each pass the largest unsorted value has 'bubbled' to the end.

It stops when a pass makes no swaps. The toy uses a longer list: 6, 2, 9, 4, 7, 1, 5. Press Reset, then Step one comparison at a time. Watch the 9 move to the end in pass 1.

PassList after the passComparisonsSwaps
Start7, 3, 9, 2, 5
13, 7, 2, 5, 943
23, 2, 5, 7, 932
32, 3, 5, 7, 921
42, 3, 5, 7, 910 β†’ stop
DECLARE Numbers : ARRAY[1:5] OF INTEGER
DECLARE Top : INTEGER
DECLARE Index : INTEGER
DECLARE Temp : INTEGER
DECLARE Swap : BOOLEAN
Numbers[1] ← 7
Numbers[2] ← 3
Numbers[3] ← 9
Numbers[4] ← 2
Numbers[5] ← 5
Top ← 5
REPEAT
  Swap ← FALSE
  FOR Index ← 1 TO Top - 1
    IF Numbers[Index] > Numbers[Index + 1]
      THEN
        Temp ← Numbers[Index]
        Numbers[Index] ← Numbers[Index + 1]
        Numbers[Index + 1] ← Temp
        Swap ← TRUE
    ENDIF
  NEXT Index
  Top ← Top - 1
UNTIL Swap = FALSE OR Top = 1
# Python has no REPEAT ... UNTIL, so a WHILE loop is used
numbers = [7, 3, 9, 2, 5]
top = 5
swap = True
while swap == True and top > 1:
    swap = False
    for index in range(top - 1):
        if numbers[index] > numbers[index + 1]:
            temp = numbers[index]
            numbers[index] = numbers[index + 1]
            numbers[index + 1] = temp
            swap = True
    top = top - 1
print(numbers)
?Why?

The swap uses `Temp` because `A ← B` then `B ← A` would lose A's value. `Temp` keeps a copy. `Top` goes down by 1 each pass because the end of the list is already sorted.

!Watch out

The loop runs to `Top - 1`, not `Top`. The last comparison is item `Top - 1` with item `Top`. Going to `Top` would compare with an item past the end.

There is something to try for this step in the IGCSE library.

How many comparisons? (extra)

This formula is not in the syllabus. It is useful for understanding why bubble sort is slow for long lists.

In the worst case every pass is needed. With n items, pass 1 makes n βˆ’ 1 comparisons, pass 2 makes n βˆ’ 2, and so on down to 1.

Adding these gives n(n βˆ’ 1) Γ· 2. Double the list and the work goes up about four times.

e.g.Example
n = 5: (5 Γ— 4) Γ· 2 = 10 comparisons. Check: 4 + 3 + 2 + 1 = 10. This matches the table above. n = 30 (a class): (30 Γ— 29) Γ· 2 = 435 n = 1000: (1000 Γ— 999) Γ· 2 = 499 500
?Why?

This shows why a sort that is fine for a class list is too slow for a million customers. Faster sorts exist, but they are not in this course.

7.5 Validation and verification

Validation and verification are different

Validation is an automatic check by the program that data is reasonable and follows set rules. It happens on input.

Verification checks that data has been copied or typed correctly from the source. It does not check if the data is sensible.

You need both. Validation accepts an age of 15 even if the student is 16. Verification catches that typing mistake.

ValidationVerification
ChecksIs the data sensible and allowed?Is the data the same as the original?
Who does itThe program, automaticallyThe user or a second entry
ExampleAge must be 11 to 18Type the password twice
!Watch out

Validation cannot prove data is correct. It only proves the data is possible. 15 is a possible age, even if the real age is 16.

Range, length, type and presence checks

Range check: a number must be between a lowest and a highest value. Example: an exam mark from 0 to 100.

Length check: the number of characters must be exact or within limits. Example: a password of 8 to 20 characters.

Type check: data must be the right data type. Example: an age must be a whole number, not 'ten'. Presence check: something must be entered. The field cannot be left blank.

DECLARE UserName : STRING
DECLARE Password : STRING
// presence check: something must be typed
OUTPUT "Enter your name: "
INPUT UserName
WHILE UserName = "" DO
  OUTPUT "Error: the name cannot be blank. Enter your name: "
  INPUT UserName
ENDWHILE
// length check: 8 to 20 characters
OUTPUT "Choose a password (8 to 20 characters): "
INPUT Password
WHILE LENGTH(Password) < 8 OR LENGTH(Password) > 20 DO
  OUTPUT "Error: use 8 to 20 characters. Try again: "
  INPUT Password
ENDWHILE
user_name = input("Enter your name: ")
# presence check: something must be typed
while user_name == "":
    user_name = input("Error: the name cannot be blank. Enter your name: ")
# length check: 8 to 20 characters
password = input("Choose a password (8 to 20 characters): ")
while len(password) < 8 or len(password) > 20:
    password = input("Error: use 8 to 20 characters. Try again: ")
print("Welcome,", user_name)
?Why?

Each check stops a different kind of bad data. A range check alone accepts a blank box in some systems. A presence check alone accepts '9999' as an age.

Format and check digit checks

Format check: data must follow a set pattern of characters. Example: a Spanish DNI is 8 digits then 1 letter, like `12345678Z`.

Check digit: an extra digit worked out from the other digits and added to the end. The computer recalculates it. If the answers differ, there is an entry error.

Try the toy: type in each box of the form and watch its checks pass or fail. Press Fill with valid data, then change the Student ID to break the format check. Type 9780140449136 in the ISBN box, then change one digit to break the check digit.

e.g.Example
ISBN-13 check digit for 978014044913? Weights alternate 1, 3, 1, 3 … 9Γ—1 + 7Γ—3 + 8Γ—1 + 0Γ—3 + 1Γ—1 + 4Γ—3 + 0Γ—1 + 4Γ—3 + 4Γ—1 + 9Γ—3 + 1Γ—1 + 3Γ—3 = 9 + 21 + 8 + 0 + 1 + 12 + 0 + 12 + 4 + 27 + 1 + 9 = 104 104 MOD 10 = 4. Check digit = 10 βˆ’ 4 = 6. Full ISBN: 9780140449136 Extra (Spain): the DNI letter is a check character too. 12345678 MOD 23 = 14, and position 14 in the official letter list is Z.
?Why?

A check digit catches common typing errors, like one wrong digit or two digits swapped. A format check would not, because the pattern still looks right.

!Watch out

A format check is about the pattern (digits here, letter there). A check digit is about a calculation. Do not mix them up.

There is something to try for this step in the IGCSE library.

Writing a validation loop

A validation loop asks for input, checks it, and asks again until it passes.

Use `REPEAT … UNTIL` or `WHILE … ENDWHILE`. Always give an error message that says what is allowed.

Python can also do a type check. `isdigit()` returns True only if every character is a digit.

e.g.Example
Inputs typed: (blank), ten, 25, 15 (blank) β†’ presence fails β†’ error ten β†’ type fails β†’ error 25 β†’ range fails (more than 18) β†’ error 15 β†’ passes β†’ Age accepted: 15
DECLARE Age : INTEGER
REPEAT
  OUTPUT "Enter your age (11 to 18): "
  INPUT Age
  IF Age < 11 OR Age > 18
    THEN
      OUTPUT "Error: age must be from 11 to 18"
  ENDIF
UNTIL Age >= 11 AND Age <= 18
OUTPUT "Age accepted: ", Age
entry = input("Enter your age (11 to 18): ")
# presence, type and range checks, repeated until the entry passes
while entry == "" or not entry.isdigit() or int(entry) < 11 or int(entry) > 18:
    print("Error: enter a whole number from 11 to 18")
    entry = input("Enter your age (11 to 18): ")
age = int(entry)
print("Age accepted:", age)
!Watch out

The condition in UNTIL is the opposite of the error condition. Error if Age < 11 OR Age > 18. Stop when Age >= 11 AND Age <= 18.

Verification: visual check and double entry

A visual check means the user reads the data on screen and compares it with the original document. Example: checking a delivery address before you pay.

A double entry check means the data is typed twice. The computer compares the two entries. If they differ, it asks again.

Double entry is used for new passwords and email addresses, where you cannot see a mistake.

DECLARE Password : STRING
DECLARE Confirm : STRING
REPEAT
  OUTPUT "Enter a new password: "
  INPUT Password
  OUTPUT "Enter the same password again: "
  INPUT Confirm
  IF Password <> Confirm
    THEN
      OUTPUT "The two entries do not match. Start again."
  ENDIF
UNTIL Password = Confirm
OUTPUT "Password saved"
password = input("Enter a new password: ")
confirm = input("Enter the same password again: ")
while password != confirm:
    print("The two entries do not match. Start again.")
    password = input("Enter a new password: ")
    confirm = input("Enter the same password again: ")
print("Password saved")
!Watch out

Double entry does not prove the data is correct. If you type the same wrong password twice, both entries match and it is accepted.

7.6 Test data

The four types of test data

Normal data: data that should be accepted. It is well inside the range.

Abnormal data: data that should be rejected. It is outside the range or the wrong type.

Extreme data: the largest and smallest values that should be accepted. Boundary data: the largest and smallest accepted values and the nearest values outside the range, which should be rejected.

TypeRange 1 to 100Expected result
Normal50, 73Accepted
Abnormal-20, 250, "ten"Rejected with an error message
Extreme1 and 100Accepted
Boundary1 and 0, 100 and 1011 and 100 accepted; 0 and 101 rejected
?Why?

Most errors hide at the edges. A programmer types `<` when they meant `<=`, and only boundary data shows it.

!Watch out

Extreme data is always accepted. Boundary data is a pair: the accepted edge value and the rejected value next to it.

There is something to try for this step in the IGCSE library.

Worked example: a test plan

A test plan lists each test, the data, the type of data and the expected result.

Scenario: a program accepts the number of days for a library loan. It must be a whole number from 1 to 21.

TestDataTypeExpected result
114NormalAccepted
230AbnormalRejected: 'Enter 1 to 21'
3"two"AbnormalRejected: 'Enter a whole number'
41Extreme (smallest)Accepted
521Extreme (largest)Accepted
60Boundary (below the range)Rejected
722Boundary (above the range)Rejected
e.g.Example
Exam answer for 'Give boundary data for 1 to 21': 1 and 0 (1 accepted, 0 rejected) 21 and 22 (21 accepted, 22 rejected)
!Watch out

Always say the expected result. 'Test data: 22' alone usually loses the mark. Write '22, rejected'.

Study it

Open the study page and go one step at a time.

The steps for this lesson

Try it

Check yourself

One question at a time. The reason shows after each answer.

Saved on this device.