Skip to content
wannacode

Linear search

In short: Linear search checks the elements one by one until it finds the one it wants or reaches the end: O(n) comparisons, and it works on an unsorted list.

Problem

The warehouse scanner

In the warehouse the products are recorded in a list in the order they arrived: flour from Monday, sugar from Tuesday, oil, rice. A worker scans a box, and the program must find the product by its barcode:

const shelf = [
{ barcode: "3800200101112", name: "Flour" },
{ barcode: "3800200104403", name: "Sugar" },
{ barcode: "3800200107251", name: "Oil" },
{ barcode: "3800200102690", name: "Rice" },
{ barcode: "3800200109958", name: "Salt" },
{ barcode: "3800200105837", name: "Coffee" },
];

The barcodes are not sorted. You cannot open the list in the middle and say "the rice is further on": the next barcode can be anything. How do you find the product, and what does it cost when there are 50 000 products and 2000 scans a day?

The idea

You look at every box

Since the order does not help, one thing is left: you start at the first box and compare its barcode with the one you look for. If it matches, you are done: you return the place. If not, you move to the next one. If the boxes run out, the product is not there.

This is linear search: you go through the elements one by one until you find the one you look for or reach the end. It returns the place (the index) or a sign for "not there": -1, because there is no place -1.

See it

The pointer on the shelf

function find(shelf, barcode) {
for (let i = 0; i < shelf.length; i++) {
if (shelf[i].barcode === barcode) {
return i;
}
}
return -1;
}
const rice = find(shelf, "3800200102690");
console.log("3800200102690 ->", rice, shelf[rice].name);
console.log("3800200100000 ->", find(shelf, "3800200100000"));
Output
3800200102690 -> 3 Rice
3800200100000 -> -1

function find(shelf, barcode) {
for (let i = 0; i < shelf.length; i++) {
if (shelf[i].barcode === barcode) {
return i;
}
}
return -1;
}
const rice = find(shelf, "3800200102690");
const missing = find(shelf, "3800200100000");
Step by step, in words
  1. The scanner reads the barcode of the rice: 3800200102690. find starts at the first box.
  2. It compares the barcode of every box with the one it looks for: flour, sugar, oil. No match.
  3. The fourth box is the rice. return 3: found after 4 comparisons.
  4. A barcode the warehouse does not have: 3800200100000. find starts from the beginning again.
  5. The pointer passes every box, and none matches.
  6. The boxes run out: return -1 after 6 comparisons. A missing product is the worst case: n comparisons for n boxes.

The rice is found after 4 comparisons. The missing barcode goes through all 6 boxes: that is the only way to say it is not there.

Try it

Fill in

What does find return when the boxes run out?

function find(shelf, barcode) {
  for (let i = 0; i < shelf.length; i++) {
    if (shelf[i].barcode === barcode) {
      return i;
    }
  }
  return ;
}

The idea

How many comparisons

The number of comparisons depends on where the product is:

  • the best case: the first box, 1 comparison;
  • the worst case: the last box or a product that is not there, n comparisons;
  • the usual case: if every place is equally likely, about n/2 on average.

The worst and the usual case grow with n, so linear search is O(n). The program counts:

function comparisons(shelf, barcode) {
let count = 0;
for (const product of shelf) {
count++;
if (product.barcode === barcode) {
return count;
}
}
return count;
}
console.log("Flour:", comparisons(shelf, "3800200101112"));
console.log("Rice:", comparisons(shelf, "3800200102690"));
console.log("Missing:", comparisons(shelf, "3800200100000"));
Output
Flour: 1
Rice: 4
Missing: 6

Run the two extreme cases on a big warehouse. We count one comparison per box:

  • The barcode is missing (worst case) O(n)
  • The first product (best case) O(1)
Algorithmn = 10n = 1,000n = 100,000
The barcode is missing (worst case)101,000100,000
The first product (best case)111
The code runs in your browser, in JavaScript. The number of operations is the same in every language, because the algorithm is the same. The time depends on the machine, so it is only for comparison. “≈” is an estimate from the curve: we do not run an n that big, so the page does not freeze.

The first box costs 1 comparison for every n: O(1). A missing product costs n: with 100 000 products that is 100 000 comparisons. The memory is O(1): one index.

Try it

Predict the output

The salt is the fifth box on the shelf. How many comparisons does the search make?

function comparisons(shelf, barcode) {
let count = 0;
for (const product of shelf) {
count++;
if (product.barcode === barcode) {
return count;
}
}
return count;
}
console.log("Salt:", comparisons(shelf, "3800200109958"));
Answer

See it

The built-ins search the same way

Every language has a ready search in a list. Inside it is the same loop:

const barcodes = [
"3800200101112", "3800200104403", "3800200107251",
"3800200102690", "3800200109958", "3800200105837",
];
console.log(barcodes.indexOf("3800200102690"));
console.log(barcodes.indexOf("3800200100000"));
console.log(barcodes.includes("3800200102690"));
console.log(shelf.findIndex((p) => p.barcode === "3800200102690"));
Output
3
-1
true
3
indexOf returns the place or -1, includes only true or false, and findIndex searches by a rule given as a function. All of them go from the first element on: O(n).

One call looks like one operation, but inside there are up to n comparisons. The built-in function is faster than your loop by some constant factor, not by an order.

Try it

Find the bug

A colleague wrote the search like this. The flour is found, and the rice "is not there":

function find(shelf, barcode) {
for (let i = 0; i < shelf.length; i++) {
if (shelf[i].barcode === barcode) {
return i;
} else {
return -1;
}
}
return -1;
}
console.log(find(shelf, "3800200101112"));
console.log(find(shelf, "3800200102690"));
Output
0
-1

Which line is the bug on?

Pick the line with the bug.

The idea

When it is right and when it is not

Linear search is the right choice when:

  • there are few products: ten or a hundred comparisons are not noticeable;
  • you search once: every faster way first needs at least n steps to prepare;
  • the data is unsorted or keeps changing, and there is nothing to maintain.

It is not when there are many searches. 2000 scans a day in 50 000 products are up to 100 000 000 comparisons. Then you prepare the data once:

  • a table barcode → product (Map): 50 000 steps once, and after that every search is O(1) on average;
  • a sorted list and binary search: sorting is O(n log n) once, and every search after it is O(log n), about 16 comparisons for 50 000.
const byBarcode = new Map();
for (const product of shelf) {
byBarcode.set(product.barcode, product);
}
console.log(byBarcode.get("3800200102690").name);
console.log(byBarcode.get("3800200100000"));
Output
Rice
undefined

The table costs memory: another n places. It is the same trade of time for memory as the set in the lesson "Space complexity".

Exercise

All the boxes of one product

Solve the task in your editor.

Stocktaking. One product may have come with several deliveries and be in several places in the list. Write findAll(shelf, barcode), which returns all places of the barcode, not just the first one. The shelf is as above, plus more rice and more salt at the end (places 6 and 7).

Output
Rice: 3, 6
Salt: 4, 7

More tasks

  • The last place. Return the last place of the barcode. Where is it better to start?
  • By name, ignoring case. Find the product by name ("rice" and "Rice" are the same). How many comparisons are there in the worst case?
  • Products under the minimum. List all products with fewer than 10 items in stock. Can you stop before the end?

Test

Check yourself

1. The list has 10 000 unsorted products. How many comparisons does linear search make for a product that is not there?
2. The product is there, and every place is equally likely. How many comparisons are needed on average for n products?
3. Why does find not return 0 when the product is not there?
4. The scanner makes 2000 searches a day in 50 000 products. Which is better?
5. When is linear search the right choice?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·