ma'am audrey's lessons

ITC 120 › Final › Searching

Searching algorithms · Lesson 1 of 1

Linear and Binary Search

This lesson teaches:Algorithm

Two ways to find one value among many: check one by one, or keep cutting the list in half.

By the end, you can:

  1. explain what a search algorithm does, and what target, found, and -1 mean;
  2. trace linear search and binary search by hand, writing every check in a table;
  3. read, fix, and complete linear and binary search in Java;
  4. compare how many checks each one needs, and choose the right one for a situation.

You need: the Arrays lesson (index, traversal), the Programming refresher (loops, else if, methods), and scratch paper.

Part 1 · The idea

Finding one thing among many

Every day, programs find one thing among thousands: your record in the enrollment system, a name in your phone's contacts, a product from its barcode. The steps a program follows to find it are called a search algorithm.

Picture two ways to find a classmate named Mia:

Where is Mia?1. A pile of forms, in no orderCris1✗Paz2✗Ben3✗Mia4✓AnaJoyCheck one form at a time until you find her.That is linear search.2. The class list, A to ZAnaBenCrisDanEvaJoyKimLizaMiaNoelPazOpen the middle: Joy.Mia comes after Joy,so the top half is out.Repeat on what is left.That is binary search.
A pile in no order must be checked one by one. A list in A-to-Z order lets you open the middle and throw away half.

Search algorithm

A search algorithm is an algorithm (a step-by-step process) for finding where a value is in a collection of data, or for finding out that it is not there.

Here are the words that come with searching:

WordMeaningWith Mia
targetthe value we are looking forMia
checklooking at one value and comparing it with the targetreading one form
foundthe target is there; the search gives back its index (its position)"Mia is the 4th form"
not foundthe target is not there; our searches give back -1"no form for Mia"

Why -1? It can never be a real index (indexes start at 0), so nobody can mistake it for a position.

This lesson teaches the two basic searches. Linear search checks one value after another, like the pile. Binary search keeps checking the middle and throwing away half, like the class list. You already played binary search: it is .

Where you see searching in IT

  • Ctrl+F in a document or web page: it reads the text from the start, like linear search.
  • Contacts on your phone are kept in A-to-Z order, so a program can find a name quickly.
  • A registrar or library system looking up a student number or a book's call number.

These illustrate the two ideas. Big systems often use the faster structures you will meet later, such as binary search trees.

Part 2 · Search 1

Linear search: one by one

Linear search

Linear search (also called sequential search) checks the values one at a time, from the first to the last, until it finds the target or runs out of values. It works on any list, sorted or not.

By hand, it follows four steps:

  1. Start at index 0.
  2. Check the value there. If it equals the target: found. Give back this index and stop.
  3. If not, move to the next index and go back to step 2.
  4. If there are no values left: not found. Give back -1.

In Java, it is a loop with an early return. Step through it on a small array in no order, looking for 93:

Walkthrough: linearSearch(arr, 93)

Use Next to go step by step, or tap a line to jump to it.

target = 93checks: 042017182933254615

target = 93

We call linearSearch(arr, 93). The method gets the array and the value to look for, the target: 93. The values are not in order, and that is fine for linear search.

Step 1 of 11
 1static int linearSearch(int[] arr, int target) { 2  for (int i = 0; i < arr.length; i++) { 3    if (arr[i] == target) { 4      return i;         // found: give back its index 5    } 6  } 7  return -1;            // checked them all: not found 8}

Here is how to read the important lines aloud:

CodeRead it as
static int linearSearch(int[] arr, int target)"a method that takes an array of ints and the value to find, and gives back an int": the index.
return i;"give back this index now." The loop and the method stop right here.
return -1;"give back -1." Java only reaches this line if the loop ended without finding the target.

How many checks?

It depends on where the target is. These two words describe the extremes:

CaseWhen it happensChecks, for n values
Best casethe target is the first value1
Worst casethe target is the last value, or not there at alln (every value)

For 6 values, that is at most 6 checks. For 1,000,000 values, it could be 1,000,000.

Mistake: giving up after the first check

Situation: a student puts return -1; in an else inside the loop:

for (int i = 0; i < arr.length; i++) {
  if (arr[i] == target) {
    return i;
  } else {
    return -1;        // gives up too early!
  }
}
return -1;
target = 93checks: 142017182933254615ireturns -1 after 1 check, but 93 is at index 3!
The first check says "no", and the else returns -1 at once. 17, 8, 93, 25, and 61 are never checked.

What goes wrong: one "no" does not mean "not found". The method stops at index 0 every time, so it only works when the target happens to be first.

Fix: remove the else. Only return -1 after the loop, when every value has said "no".

Part 3 · Search 2

Binary search by hand

Linear search never uses the order of the values. When the values are sorted (in order, smallest to largest), one check can tell us much more: if the middle value is too small, everything to its left is too small too.

Binary search

Binary search finds a target in a sorted list. It checks the middle value. If that is the target, it is done. If the target is smaller, it throws away the right half; if the target is larger, it throws away the left half. It repeats on the half that is left until it finds the target or nothing is left. ("Binary" means "in two": each check splits the list in two.)

Three numbers keep track of the part that is still possible:

NameMeaning
lowthe first index that is still possible (starts at 0)
highthe last index that is still possible (starts at the last index)
midthe middle index: (low + high) / 2, rounded down

"Rounded down" is just how Java : (0 + 11) / 2 is 5, not 5.5.

Course convention

In this course, mid always rounds down, as Java does. A few books round up instead; that changes which values are checked, so use rounding down on our quizzes and exams.

The steps, by hand:

  1. Set low = 0 and high = the last index.
  2. While low ≤ high: find mid and check the value there.
    • Equal to the target: found. Give back mid.
    • Smaller than the target: the target is to the right. Set low = mid + 1.
    • Bigger than the target: the target is to the left. Set high = mid - 1.
  3. If low passes high, nothing is left: not found. Give back -1.

Binary search for 71, by hand

Use Next to go through the steps.

target = 71checks: 0409115221327434542656763871980108811lowhigh

Binary search for 71. The list is sorted. Start with the whole list: low = 0, high = 11.

Step 1 of 8

On paper (and on exams), write one row per check:

lowhighmidarr[mid]Then
01153434 < 71: low = 6
61186363 < 71: low = 9
911108080 > 71: high = 9
99971found: return 9

4 checks. Linear search would have needed 10 (indexes 0 to 9).

Mistake: binary search on unsorted data

Situation: a student runs binary search on {30, 10, 50, 20, 40}, looking for 20.

target = 20checks: 1300101502203404lowmidhigh20 < 50, so it throws away the right side...target = 20checks: 2300101502203404low midhigh...but 20 was at index 3. Result: -1 (wrong!)
The values are not in order, so "20 < 50" does not mean 20 is on the left. The search throws away the half that holds 20.

What goes wrong: binary search trusts the order. Without it, throwing away half can throw away the target, so the answer is wrong (-1) even though 20 is there.

Fix: sort the values first, or use linear search.

Part 4 · Try it

The search lab

Run both searches on the same sorted array and count the checks. Try 71, then 4 (the first value: which search wins now?), then 88, then a number that is not there.

Part 5 · In code

Binary search in Java

Each step of the by-hand rule becomes one or two lines. Step through it looking for 20, which is not in the array, to see how the method knows when to stop:

Walkthrough: binarySearch(arr, 20)

Use Next to go step by step, or tap a line to jump to it.

target = 20checks: 0409115221327434542656763871980108811

target = 20

We call binarySearch(arr, 20) on the sorted array. 20 is not in it, so we will see how the method finds out.

Step 1 of 11
 1static int binarySearch(int[] arr, int target) { 2  int low = 0; 3  int high = arr.length - 1; 4  while (low <= high) { 5    int mid = (low + high) / 2; 6    if (arr[mid] == target) { 7      return mid;              // found 8    } else if (arr[mid] < target) { 9      low = mid + 1;           // target is to the right10    } else {11      high = mid - 1;          // target is to the left12    }13  }14  return -1;                   // nothing left: not found15}

Here is how to read the key lines aloud:

CodeRead it as
while (low <= high)"while there is at least one index left to check."
int mid = (low + high) / 2;"the middle index, rounded down."
low = mid + 1;"the target is to the right of mid; mid itself is already checked."
high = mid - 1;"the target is to the left of mid."

Both searches in one program

Here is everything in one runnable file. Run it and match each output line to its comment:

 1public class Main {
 2  static int linearSearch(int[] arr, int target) {
 3    for (int i = 0; i < arr.length; i++) {
 4      if (arr[i] == target) {
 5        return i;
 6      }
 7    }
 8    return -1;
 9  }
10
11  static int binarySearch(int[] arr, int target) {
12    int low = 0;
13    int high = arr.length - 1;
14    while (low <= high) {
15      int mid = (low + high) / 2;
16      if (arr[mid] == target) {
17        return mid;
18      } else if (arr[mid] < target) {
19        low = mid + 1;
20      } else {
21        high = mid - 1;
22      }
23    }
24    return -1;
25  }
26
27  public static void main(String[] args) {
28    int[] pile = {42, 17, 8, 93, 25, 61};
29    System.out.println(linearSearch(pile, 93));   // 3
30    System.out.println(linearSearch(pile, 50));   // -1
31
32    int[] sorted = {4, 9, 15, 21, 27, 34, 42, 56, 63, 71, 80, 88};
33    System.out.println(binarySearch(sorted, 71)); // 9
34    System.out.println(binarySearch(sorted, 20)); // -1
35  }
36}

▶ This program runs as is. Try it in the Programiz online compiler: tap Copy, paste it there, and press Run.

Two common bugs in binary search

  1. < instead of <=.
    while (low < high) {        // should be <=
      int mid = (low + high) / 2;
      ...
    }
    When only one index is left, low equals high, and low < high is false, so that last value is never checked. Searching for 15 in {4, 9, 15} returns -1 even though 15 is there.
  2. low = mid instead of low = mid + 1.
    } else if (arr[mid] < target) {
      low = mid;                  // should be mid + 1
    }
    With {4, 9} and target 9: mid = 0, 4 < 9, so low = 0 again. Nothing changes, and the loop runs forever. The +1 (and -1) make the part that is left smaller every time.

Part 6 · Why this matters

Which search is faster?

Count the checks in the worst case (the target is not there):

Number of valuesLinear searchBinary search
1010 checks4 checks
100100 checks7 checks
1,0001,000 checks10 checks
1,000,0001,000,000 checks20 checks
Binary search on 1,000 sorted valuesvalues still possible after each check (worst case)1,000start500after 1250after 2125after 362after 431after 515after 67after 73after 81after 9About 10 checks, even with 1,000 values.Linear search could need all 1,000.
Each check throws away half. That is why the binary column grows so slowly.

Look at the binary column: every time the number of values doubles, binary search needs only one more check. Linear search needs twice as many.

So is binary search always better? No. It has two conditions:

  1. The values must be sorted. Sorting takes work too (that is what the sorting lessons are about). If a list is searched only once, sorting it first can cost more than a simple linear search.
  2. It needs to jump to the middle in one step, which an array can do but a linked list cannot (see ).
Array: jump straight to the middle491521273442arr[3]: one step, like any indexLinked list: walk from head to reach it4hop 19hop 215hop 321Reaching the middle already costs half the list,so binary search loses its speed.
In an array, the middle is one step away. In a linked list, you must walk there.

Here is how to choose:

SituationBetter choice
A short list, or a list in no order that you search onceLinear search
A linked listLinear search
A big sorted array that is searched many times (student numbers, a price list)Binary search

Good to know: books describe this growth with short names. Linear search is O(n) ("order n": the work grows with the number of values). Binary search is O(log n) ("order log n": the work grows with how many times you can halve n). You will see these names again when the course analyzes algorithms.

Part 7 · Java's own tools

Searching with Java's Arrays

In real programs, you rarely write binary search yourself: Java already has it. Arrays.sort puts an array in order, and Arrays.binarySearch searches it. Both live in java.util.Arrays, so the file starts with an import line that tells Java where to find them.

 1import java.util.Arrays;
 2
 3public class Main {
 4  public static void main(String[] args) {
 5    int[] arr = {56, 4, 88, 21, 71, 9};
 6    Arrays.sort(arr);                                 // put it in order first
 7    System.out.println(Arrays.toString(arr));         // [4, 9, 21, 56, 71, 88]
 8    System.out.println(Arrays.binarySearch(arr, 71)); // 4
 9    System.out.println(Arrays.binarySearch(arr, 20)); // -3 (negative: not found)
10  }
11}

▶ This program runs as is. Try it in the Programiz online compiler: tap Copy, paste it there, and press Run.

Two things to notice:

  • Arrays.binarySearch also needs a sorted array. On an unsorted array, its answer cannot be trusted (like ).
  • When the target is missing, it gives back a negative number, but not always -1 (here, -3). Check for "less than 0", not "equal to -1".

Part 8 · Your turn

Practice

On paper

  1. Linear search on {12, 5, 30, 7, 19}. (a) Looking for 7: what does it return, and after how many checks? (b) Looking for 40?
  2. Binary search on {2, 6, 11, 17, 23, 29, 35, 40, 48, 52} (indexes 0 to 9). Fill in a low / high / mid / arr[mid] / Then table for (a) target 11 and (b) target 50. The first row of (a) is done for you:
    lowhighmidarr[mid]Then
    0942323 > 11: high = 3
  3. Spot the bug. This code should print "found at 2". What does it print, and which line is wrong?
     1int[] arr = {4, 9, 15};
     2int low = 0, high = 2;
     3while (low < high) {
     4  int mid = (low + high) / 2;
     5  if (arr[mid] == 15) {
     6    System.out.println("found at " + mid);
     7    break;
     8  } else if (arr[mid] < 15) {
     9    low = mid + 1;
    10  } else {
    11    high = mid - 1;
    12  }
    13}
  4. Linear or binary? (a) 30 names in sign-up order, searched once. (b) 50,000 student numbers kept sorted, searched all day by the registrar. (c) A linked list of songs in a playlist.
Show the answers

For self-study, not for grading. All answers were checked by running the code in Java.

  1. (a) Returns 3 after 4 checks (12, 5, 30, 7). (b) Returns -1 after 5 checks: every value had to be checked.
  2. (a) Target 11:
    lowhighmidarr[mid]Then
    0942323 > 11: high = 3
    03166 < 11: low = 2
    23211found: return 2
    (b) Target 50:
    lowhighmidarr[mid]Then
    0942323 < 50: low = 5
    5974040 < 50: low = 8
    8984848 < 50: low = 9
    9995252 > 50: high = 8
    98——low > high: return -1
  3. It prints nothing. Line 3 should be while (low <= high). After the first check, low becomes 2 and high is 2: one value is left, but 2 < 2 is false, so 15 is never checked.
  4. (a) Linear: short, in no order, searched once. (b) Binary: big, sorted, searched many times. (c) Linear: a linked list cannot jump to its middle.

Your coding task: count the votes

In a class election, each vote is a candidate's number. Finish countOf so it returns how many times target appears in the array. It is linear search that keeps going after a match, and counts. Write about 5 lines where it says YOUR CODE, then run it: the three printed numbers must match the comments.

 1public class Main {
 2  static int countOf(int[] arr, int target) {
 3    int count = 0;
 4    // YOUR CODE: look at every value in arr,
 5    // and add 1 to count when it equals target.
 6
 7    return count;
 8  }
 9
10  public static void main(String[] args) {
11    int[] votes = {3, 1, 3, 2, 3, 1};
12    System.out.println(countOf(votes, 3));   // expected: 3
13    System.out.println(countOf(votes, 2));   // expected: 1
14    System.out.println(countOf(votes, 5));   // expected: 0
15  }
16}

▶ This program runs as is. Try it in the Programiz online compiler: tap Copy, paste it there, and press Run.

Show one possible answer
 1static int countOf(int[] arr, int target) {
 2  int count = 0;
 3  for (int i = 0; i < arr.length; i++) {
 4    if (arr[i] == target) {
 5      count++;
 6    }
 7  }
 8  return count;
 9}

Output: 3, 1, 0. There is no early return here: to count every match, the loop must visit every value.

Part 9 · Check yourself

Self-check

Not graded. Tap an answer to see if you got it, and read why.

Key takeaways

  1. A search gives back the target's index, or -1 when it is not there.
  2. Linear search checks one value after another. It works on any order, but may need every value (n checks).
  3. Binary search checks the middle and throws away half. It needs sorted data and an array, and needs only about 20 checks for 1,000,000 values.
  4. In Java: while (low <= high), mid = (low + high) / 2, then low = mid + 1 or high = mid - 1.
  5. Java's Arrays.binarySearch does it for you, on a sorted array.

Next lesson: Basic sorting. Binary search needs sorted values, so next you learn how to sort them. (A binary search tree, from the midterm, uses the same halving idea without needing a sorted array.)

References

  1. A. Bhargava, Grokking Algorithms. Manning, 2016, Chapter 1 (binary search).
  2. R. Sedgewick and K. Wayne, Algorithms, 4th ed. Addison-Wesley, 2011, Section 1.1 (binary search). algs4.cs.princeton.edu
  3. Programiz, "Linear Search" and "Binary Search." programiz.com/dsa
  4. Oracle, "Class Arrays," Java SE 21 API (sort, binarySearch). docs.oracle.com
  5. ITC 120 Course Syllabus (Search Algorithms), Davao Oriental State University.