We spoke a bit about searching arrays so far, and we have always
done it like this:
public static int search(String [] roster, String student) {
for (int i = 0; i < roster.length; i++) {
if (roster[i].equals(student)) {
return i;
}
}
return -1;
}
This version of search uses the algorithm we are most familiar with,
which is called linear (sequential) search
Linear Search is defined as a
sequential search algorithm that
starts at one end and goes through each element of a list until
the desired element is found, otherwise the search continues till
the end of the data set.
In the Linear Search Algorithm:
-
Every element is considered as a potential match for the key and
checked for the same
-
If any element is found equal to the key, the search is successful
and the index of that element is returned
-
If no element is found equal to the key, the search yields “No
match found”
We can define the algorithm with four main steps:
- Traverse the array
- Match the key element with array element
-
If key element is found, return the index position of the array
element
- If key element is not found, return -1
For example: Consider the array
int [] arr = {10, 50, 30, 70, 80, 20, 90, 40} and
key (the element we are searching for) = 30
We will start searching from the first element (index 0) and compare
the key with each element (arr[i])
Comparing the key with first element arr[0]. Since they are not
equal, the iterator moves to the next element as a potential match.
Comparing key with next element arr[1]. Since they are also not
equal, the iterator moves to the next element as a potential match.
Now when comparing arr[2] with key, the value matches.
So the Linear Search Algorithm will yield a successful message and
return the index of the element when key is found (here 2).
If the array elements are not in order, there is no way to search
faster than linear/sequential search. We have to look at every element, because otherwise we cannot be
certain the element we want is not there. But if the elements are in
order, we can use better algorithms!
When we look for a word in a dictionary, we don't just search page
by page from front to back.
Since the words are in
alphabetical order, you probably want to use a
binary search algorithm:
- Start on a page near the middle of the dictionary.
-
Compare a word on the page to the word you are looking for. If you
find it, stop.
-
If the word on the page comes before the word you are looking for,
flip to somewhere later in the dictionary and go to step 2.
-
If the word on the page comes after the word you are looking for,
flip to somewhere earlier in the dictionary and go to step 2.
If you find two adjacent words on the page and your word comes
between them, you can conclude that your word is not in the
dictionary.
Binary Search is defined as a searching algorithm
used in a sorted array by repeatedly dividing the search interval
in half.
Getting back to our previous example of a roster of students, we can
write a faster version of search if we know the students are in
order (and they usually are!):
public static int binarySearch(String [] roster, String student) {
int low = 0;
int high = roster.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2; // step 1
int comp = roster[mid].compareTo(student);
if (comp == 0) { // step 2
return mid;
} else if (comp < 0) { // step 3
low = mid + 1;
} else { // step 4
high = mid - 1;
}
}
return -1;
}
This version is called iterative as the approach iterates through
the array.
First, we declare low and high variables to represent
the range we are searching. Initially we search the entire array,
from 0 to length - 1.
Inside the while loop, we repeat the four steps of binary
search:
-
Choose an index between low and high – call it mid – and compare
the student name at mid to the target.
- If you found the target, return the index.
-
If the name at mid is lower than the target (lexicographically
before), search the range from mid + 1 to high
-
If the name at mid is higher than the target (lexicographically
after), search the range from low to mid - 1.
If low exceeds high, there are no Strings in the range, so we
break out of the loop and return -1. Notice that this algorithm depends on the String .compareTo()
method.
We can also write this algorithm recursively (the technique of
making a method/function call itself):
public static int binarySearch(String [] roster, int low, int high, String student) {
if (high >= low) {
int mid = low + (high - low) / 2;
int comp = roster[mid].compareTo(student);
if (comp == 0)
return mid;
if (comp < 0)
return binarySearch(arr, mid + 1, high, x);
return binarySearch(arr, low, mid - 1, x);
}
return -1;
}
Let's look at another example:
Consider an array
int [] arr2 = {2, 5, 8, 12, 16, 23, 38, 56, 72, 91}, and the
key/target = 23.
The first step:
Calculate the mid and compare the mid element with the key. If
the key is less than mid element, move to left and if it is
greater than the mid then move search space to the right.
Key (i.e., 23) is greater than current mid element (i.e., 16). The
search space moves to the right.
Key is less than the current mid 56. The search space moves to the
left.
The second step:
If the key matches the value of the mid element, the element is
found and stop search.