Linear search
On This Lesson 11 topics
Lesson Overview
The last lesson introduced two ways to find "Mona" in a list: read from the top, or open in the middle. This lesson writes the first one in Java. Linear search checks each element in order, starting at index 0, until it finds the target or runs out of elements.
It is the simplest searching algorithm and it works on any array, sorted or not. It is also the baseline we will compare faster algorithms against, so we will practise counting its comparisons.
Why this matters: a surprising amount of real code is a linear search in disguise (look through the list for the matching id). Knowing exactly what it costs lets you decide when it is fine and when it is not.
This lesson builds on "What an algorithm is" and on arrays, for loops, and methods.
Learning Objectives
By the end of this lesson you will be able to:
- Describe linear search in plain steps.
- Implement
linearSearch(int[] a, int target)that returns the index of the target, or-1if it is absent. - Explain why
-1is a sensible "not found" value. - Trace a linear search with a variable table.
- Count the comparisons for the best, worst, and a typical case.
- Adapt the same loop to search an array of
Stringvalues. - Decide when linear search is a good choice.
Written Explanation
The idea
Think of looking for a book on an unsorted shelf. You start at one end, check each book, and stop when you find yours. If you reach the other end, it is not there.
In steps:
- Start at index 0.
- Compare the element at this index with the target.
- If they are equal, stop and report this index.
- Otherwise move to the next index.
- If there are no more elements, report "not found".
The code
static int linearSearch(int[] a, int target) {
for (int i = 0; i < a.length; i++) {
if (a[i] == target) return i;
}
return -1;
}Three details:
- The method returns the index, not the value. The caller already knows the value; the index tells where it is.
return i;inside the loop ends the whole method at once, so we stop looking after the first match.return -1;is reached only if the loop finished without finding the target. Valid array indexes start at 0, so-1can never be mistaken for a real position. This is the convention used by many Java methods. The calling code must check for it:
int pos = linearSearch(ids, 1093);
System.out.println(pos >= 0 ? "found at " + pos : "not found");Comparing strings
For int we compare with ==. For String values you learned that == is the wrong tool and that equals compares the text. The same loop works with a small change, here ignoring upper and lower case:
static int linearSearch(String[] a, String target) {
for (int i = 0; i < a.length; i++) {
if (a[i].equalsIgnoreCase(target)) return i;
}
return -1;
}Two methods with the same name but different parameter types are legal: this is overloading from the methods module. Java picks the right one from the argument types.
Counting comparisons
The work of the loop is the comparison a[i] == target. How many happen depends on where the target is. For an array of n elements:
| Situation | Comparisons |
|---|---|
| Best case: target is first | 1 |
| Worst case: target is last, or not present | n |
| Typical successful search | somewhere between, about n / 2 if every position is equally likely |
The worst case is the number to remember, because it is what you must be ready for. It is also easy to state: with 1,000 elements, 1,000 comparisons. Double the data and the worst case doubles.
To measure it instead of guessing, add a counter. A counter field makes the idea visible:
static int comparisons = 0;
static int countedSearch(int[] a, int target) {
comparisons = 0;
for (int i = 0; i < a.length; i++) {
comparisons++;
if (a[i] == target) return i;
}
return -1;
}Duplicates and edge cases
- Duplicates. If the target appears more than once, this version returns the first index, because it stops at the first match. To find the last, loop from the end.
- Empty array.
a.lengthis 0, the loop body never runs, and the method returns-1. Correct, with no special code. - One element. Works as normal.
- Not found. Returns
-1after checking every element.
When linear search is the right choice
- The array is small. For ten items, nothing faster is worth the extra code.
- The data is not sorted and you search only once or twice. Sorting first would cost more than the search.
- You want the first match in the original order.
When the array is large, sorted, and searched many times, a better algorithm exists. That is the next lesson.
Examples
Example 1: finding a value (simple)
int[] data = {14, 3, 27, 9, 3, 18};
System.out.println(linearSearch(data, 27));
System.out.println(linearSearch(data, 3));
System.out.println(linearSearch(data, 99));
System.out.println(linearSearch(new int[]{}, 5));Output:
2
1
-1
-1The second line shows the duplicate rule: 3 appears at indexes 1 and 4, and the method reports the first. The last line is the empty-array edge case.
Trace for target 27:
| i | a[i] | a[i] == 27? |
|---|---|---|
| 0 | 14 | no |
| 1 | 3 | no |
| 2 | 27 | yes, return 2 |
Example 2: counting the best and worst case (practical)
countedSearch(data, 99);
System.out.println(comparisons);
countedSearch(data, 14);
System.out.println(comparisons);Output:
6
1The array has 6 elements. A missing target costs all 6 comparisons (the worst case), and a target in the first position costs 1 (the best case). Doubling the array to 12 elements would double the worst case to 12.
Example 3: searching names, ignoring case (realistic)
A grade-book program stores names in an array and the teacher types a name to look up:
String[] names = {"Adam", "Mona", "Sara"};
System.out.println(linearSearch(names, "mona"));
System.out.println(linearSearch(names, "Omar"));Output:
1
-1"mona" matches "Mona" because of equalsIgnoreCase. The caller turns the index into a friendly message, and -1 into "no such student". The student arrays from the arrays module were searched in exactly this way.
Backend Insight
Looking for a record by id, email, or username is the most common operation in a backend. If the records sit in an unsorted list, a linear search is what happens: the program checks them one after another. That is fine for a hundred records and a problem for ten million records searched on every request.
Databases solve this by building an index, a separate sorted structure that lets them jump to the right place instead of scanning every row. When someone says "this query does a full table scan", they are describing a linear search over the whole table. You do not need the details now. You only need to recognise the pattern: checking every item is simple, and it gets slower in step with the data.
Common Mistakes
Mistake 1: Returning -1 inside the loop
for (int i = 0; i < a.length; i++) {
if (a[i] == target) return i;
else return -1; // wrong
}This returns -1 after checking only the first element. "Not found" is known only after the loop has checked everything, so return -1; belongs after the loop.
Mistake 2: Off-by-one loop bounds
- Incorrect:
i <= a.length(readsa[a.length], which does not exist and throwsArrayIndexOutOfBoundsException). - Incorrect:
i < a.length - 1(never checks the last element, so a target in the last position is reported missing). - Correct:
i < a.length.
Mistake 3: Comparing strings with ==
For String targets use equals or equalsIgnoreCase. == compares whether two names refer to the same object, not whether the text matches, and gives confusing results.
Mistake 4: Forgetting to check for -1
Using the result directly as an index, for example data[linearSearch(data, 99)], throws an exception when the target is missing. Always test pos >= 0 first.
Exercises
Try each exercise yourself before opening the solutions.
Level A: Foundation
A1. What does linearSearch return for {5, 8, 2} and target 2? For target 7?
Show solution A1
A1. For target 2 it returns 2 (the index of the 2). For target 7 it returns -1.
A2. Why is -1 used for "not found" and not 0?
Show solution A2
A2. 0 is a valid index (the first element), so returning it for "not found" would be confused with "found at the start". -1 can never be a real index.
A3. How many comparisons does a worst-case linear search make on 250 elements?
Show solution A3
A3. 250 comparisons.
Level B: Application
B1. Write static int lastIndexOf(int[] a, int target) that returns the last position of the target, or -1.
Show solution B1
B1.
static int lastIndexOf(int[] a, int target) {
for (int i = a.length - 1; i >= 0; i--) {
if (a[i] == target) return i;
}
return -1;
}On {14, 3, 27, 9, 3, 18} with target 3 it returns 4.
B2. Write static int countMatches(int[] a, int target) that returns how many times the target appears. What does it return for an empty array?
Show solution B2
B2.
static int countMatches(int[] a, int target) {
int count = 0;
for (int v : a) {
if (v == target) count++;
}
return count;
}For an empty array it returns 0, because the loop never runs.
B3. Trace linearSearch on {9, 4, 7, 4} for target 7 with a table of i, a[i], and whether it matched.
Show solution B3
B3.
| i | a[i] | match? |
|---|---|---|
| 0 | 9 | no |
| 1 | 4 | no |
| 2 | 7 | yes, return 2 |
Level C: Challenge
C1. Write static int[] allIndexes(int[] a, int target) that returns every index where the target appears, as a new array (empty if none). Test with {14, 3, 27, 9, 3, 18} and target 3.
Show solution C1
C1.
static int[] allIndexes(int[] a, int target) {
int count = 0;
for (int v : a) {
if (v == target) count++;
}
int[] result = new int[count];
int k = 0;
for (int i = 0; i < a.length; i++) {
if (a[i] == target) result[k++] = i;
}
return result;
}Run on {14, 3, 27, 9, 3, 18} with target 3, Arrays.toString prints [1, 4]; with target 5 it prints []. The first loop counts so that we know how big the result array must be (arrays have a fixed size).
C2. A friend says: "Linear search on a sorted array can stop early." Describe how, for an array sorted ascending, and say what that changes in the worst case.
Show solution C2
C2. If the array is sorted ascending, stop as soon as a[i] > target, because every later element is even larger and cannot be the target. For missing targets this can save steps. The worst case does not change: a target bigger than everything still forces all n comparisons.
Mini Challenge
Write a small program with an array of at least eight order ids (not sorted). Ask the user (with Scanner) for an id, call linearSearch, and print either "Order found at position X" or "Order not found". Run it for the first element, the last element, a missing id, and an id typed twice in the array. Write down how many comparisons your counter reports in each case.
Check your work: the not-found case prints the message and does not crash, and the counts match the best and worst cases from the table.
Summary & Next Lesson
Key takeaways
- Linear search checks elements from index 0 in order and returns the index of the first match, or
-1. -1is safe as "not found" because it is never a valid index. Callers must check for it.- It works on any array, sorted or not, and handles the empty array without special code.
- Worst case (last or missing target):
ncomparisons. Double the data, double the work. - It is a good choice for small arrays and one-off searches, and it is the baseline for comparing faster methods.
Next lesson
The next lesson, "Binary search", shows how to find a value in a sorted array in about ten steps for a thousand items, by discarding half of the remaining elements at each look.
Self-check
- What does
linearSearchreturn when the target is absent? - Where must
return -1;be placed in the method? - How many comparisons does the worst case need for
nelements? - If the target appears twice, which index is returned?
- Name one situation where linear search is a good choice.
Show answers
-1.- After the loop, so that every element has been checked first.
n.- The first one, because the method returns at the first match.
- A small array, or an unsorted array that is searched only once or twice.
References
- Oracle, Arrays (Java SE 21 API). The library's own
binarySearchalso reports "not found" with a negative number, which supports the idea that a negative return signals absence;-1for linear search is a common course convention rather than a language rule. - The comparison counts and the typical-case estimate of about n / 2 are simple counting arguments, and the code outputs shown were produced by compiling and running the examples on JDK 21.
- The database "full table scan" and index remark in Backend Insight is a general description that was not checked against a specific database manual.
Practice
Apply this lesson with the module's lab, exercises and quiz.
Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.