Returning Values from Methods
A linear search checks each item of an array in turn. It finishes as soon as it finds the item, and it can conclude the item is absent only after checking every position.
Why Start With the Simplest Search
Suppose you have an array of integers and you need to know whether a particular value appears in it, and if so, where. The array gives you no hints about where the value might be. It is not sorted, and nothing else tells you which position to try first. What is the most direct method you could use?
The most direct method is also the most obvious one: look at each item in the array in turn, and check whether that item is the one you are looking for. If you find it, the search is finished. If you look at every item without finding the one you want, you can be sure the item is not in the array. This method is called a linear search. In this article you will start from code that performs the search, predict its result before running it, and then trace the mechanism that produces that result.
Reading the find Method
The following Java method searches an array of ints for a specified integer. It takes the array A and the integer N to look for. Read it once for its overall shape before you worry about individual lines. Notice that the declared return type is int, so the method hands back a single integer to whoever calls it.
- The return type int tells the caller that exactly one integer comes back
- The parameters A and N are the array to search and the value to look for
- The loop variable index is the only thing that moves through the array
- return index exits the method on the first match
- return -1 is reached only when the loop finishes without a match
Two return statements appear in this method, and they play different roles. The one inside the if block is reached only when a match has been found. The one after the loop is reached only when every position has been checked and none matched. Which of these two statements the method executes determines what the caller receives, so the rest of this article follows that choice.
Predicting Before You Run
Before you move on, make a prediction. Consider the array {4, 8, 8, 2} and a call to find with N equal to 8. The value 8 appears twice, at positions 1 and 2. Decide which index you expect find to return, and state the reason from the loop itself rather than from guessing.
What do you think happens?
For the array {4, 8, 8, 2}, what index does find(A, 8) return?
Reveal answer
1
The loop starts at index 0, where the element 4 does not equal 8, so nothing is recorded and the loop continues. At index 1 the element 8 equals N, so the method returns 1 immediately. The second 8 at index 2 is never examined, because the method has already left the loop.
Tracing the Loop Position by Position
The loop variable index is the only thing that moves through the array. It begins at 0 and increases by one each time the loop body finishes, stopping once index reaches the length of the array. On each pass the method asks a single question: does the element at this position equal N? If the answer is no, nothing is recorded and the loop moves on. If the answer is yes, the method leaves immediately and reports the position.
The diagram shows that the loop never looks ahead. The value at index 2 is an 8 as well, but the method never gets there. This is the first consequence of the design: the search stops at the first position that satisfies the comparison.
Mapping Positions to the Returned Index
The method has no memory of earlier mismatches. It does not count them or keep a list of places it has checked. Each position is judged alone, and the answer is determined by the first position that satisfies the comparison. Because of this, when several positions hold the same value, the index returned is always the smallest of them.
In the diagram, position 1 is highlighted because it is the one the search returns. Position 2 also holds an 8, yet it is never the result. If you changed the array to {4, 8, 8, 2} and asked for the 8 again, you would still get 1, not 2, because index 1 is the smallest position holding that value.
Two Ways the Search Can Stop
The method can finish in exactly two ways. One is through a match, which returns an index. The other is through exhausting the array, which returns -1. The flowchart below shows the same decisions as the method, in the order control moves between them.
The branch that returns an index is taken as soon as a match appears, so it can exit the loop while many positions remain unchecked. The branch that returns -1 can only be reached after the loop condition fails, which means every position has been examined without success. This asymmetry is what lets the method conclude absence safely: it cannot claim the value is missing until it has looked everywhere.
Index Versus -1 for the Caller
A caller receives a single int, and that int must carry two different meanings: either the position where the value was found, or a signal that it was not found. The method relies on -1 for the second meaning. This choice is safe because -1 is never a valid index, so no real position can be confused with the not-found signal.
| Returned value | What it means | Where it comes from | What the caller should do |
|---|---|---|---|
| A value 0 or greater | The value was found at this index, and this is the smallest index holding it | return index inside the loop | Use the index to read or locate the element |
| -1 | The value is not in the array | return -1 after the loop finishes | Treat the value as absent, and do not use it as an index |
Interpreting the two possible return values of find
1
-1find(A, 8)returns 1, the smallest index holding 8find(A, 5)returns -1, because 5 never appears in the array
Mistakes Beginners Make
Common mistake Expecting the last matching position to be returned
What it looks likeFor {4, 8, 8, 2} and N = 8, expecting find to return 2.
Why it failsThe loop exits at the first position where the comparison succeeds, so the later 8 at index 2 is never examined.
Do this insteadExpect the smallest matching index, which here is 1.
Common mistake Treating -1 as a position in the array
What it looks likeWriting A[find(A, 5)] without checking the result first.
Why it fails-1 is the not-found signal, and it is never a valid index, so reading that position fails.
Do this insteadCheck whether the result is -1 before using it as an index.
Common mistake Concluding absence before the loop has finished
What it looks likeAssuming 5 is missing after checking only the first two positions.
Why it failsThe method reports -1 only after every position has been checked without a match.
Do this insteadLet the loop run to the end of the array before accepting that the value is absent.
Common mistake Assuming the method remembers earlier mismatches, when each position is judged alone
Practice: Trace a Search
Given the array {7, 3, 9, 3, 5} and the call find(A, 3), state the value returned before you check it. Then list each index the loop visits, and say at which index the loop stops and why.
Hints
- Start at index 0 and compare A[index] with N on each pass.
- Ask at which index the first equal element appears, not the last one.
- A call with a value that never appears would instead end with -1 after the loop finishes.
Key Takeaways
- A linear search checks each position of an array in turn, starting at index 0, and stops as soon as the sought value is found.
- The method can conclude that a value is absent only after every position has been checked without a match, which is why it returns -1 only after the loop ends.
- When several positions hold the same value, find returns the smallest of those indices, because the first match ends the search.
- The return value -1 is a safe not-found signal because it is never a valid index, so callers must check for it before using the result as a position.
- When a result surprises you, find the first iteration where the behavior departed from your prediction, since that point usually reveals the fault.