Searching and Sorting
Searching
An important use of computers is for looking up data—how often have you turned on your computer just
to “google” for something?
The process of looking up data is called
searching
.
Common examples would be to look up a person
in the telephone book or to search for the meaning of a word in a dictionary. The efficiency of searching
depends on whether the data being searched is sorted or not. When the input data list is not sorted, we
have little choice but to do a linear
sequential search
, stepping through the list onebyone until a match is
found. This is what we have to do in the case of the telephone book when we search a person by his/her
phone number.
More interesting is the case of a sorted input list. We formulate the problem as follows:
Problem of searching a sorted list:
Given a list
A
with a
nondecreasing
sequence of integers and
x
,
find the smallest index
i
such that
A
[
i
]
≥
x
.
If all elements of
A
are smaller than
x
, return
A.size()
.
The definition is perhaps a bit more complicated than expected, since we also want to say precisely what
should happen when the element
x
we are searching is
not
in the list. This is often important, for instance
because we then want to insert it at this position, or because we want to find the nearest element in the list.
Once again, the most elegant and clear solution to the problem of searching a sorted list is a recursive
solution. We compare
x
with the middle element of the list
A
, and recursively search in the left half or the
right half.
This algorithm is called a
binary search
, since we are making a binary decision in every step.
Here is code for recursive binary search.
// Start from calling this method in the main method.
int find(int x, List<Integer> A) {
return find(x, A, 0, A.size()  1);
}
// Precondition: A[k] < x for k < i and A[k] >= x for k > j.
// Output is in {i, . . . j + 1}
int find(int x, List<Integer> A, int i, int j) {
if (j < i)
return i;
int mid = (i + j) / 2;
if (A.get(mid) < x) return find(x, A, mid+1, j);
else
return find(x, A, i, mid1);
}
Correctness
Does this program really work? We use a precondition and an output condition to help us
understand why this program is correct, where
precondition
means a condition or predicate that must always
be true just prior to the execution of some section of code and an
output condition
means what the desirable
output should be. Checking preconditions is similar to mathematical induction: the base case is to show
that the precondition holds before the first recursive call, the inductive step is to show that the precondition
is true in each recursive call.
We can prove the correctness of the program above by showing that the precondition and output condition
hold through this program.
Base case:
Before the first recursive call,
i
= 0 and
j
=
A.size()

1, which means that there is no
k
such
that
k < i
or
k > j
, and so the precondition holds before the first call. Also, we can easily see that the
output range will be
{
0
,
1
, . . . ,
A.size()
}
, where
A.size()
as an output can happen when
x
is larger
than all elements in the list.