A Recursive Binary Search
A Recursive Binary Search
Remember the binary search we discussed in Chapter 2, “Arrays”? We wanted to find
a given cell in an ordered array using the fewest number of comparisons. The solu- tion was to divide the array in half, see which half the desired cell lay in, divide that half in half again, and so on. Here’s what the original find() method looked like:
//----------------------------------------------------------- public int find(long searchKey)
{ int lowerBound = 0; int upperBound = nElems-1; int curIn;
while(true) { curIn = (lowerBound + upperBound ) / 2; if(a[curIn]==searchKey)
return curIn; // found it else if(lowerBound > upperBound) return nElems; // can’t find it else // divide range { if(a[curIn] < searchKey)
lowerBound = curIn + 1; // it’s in upper half else
upperBound = curIn - 1; // it’s in lower half } // end else divide range } // end while } // end find() //-----------------------------------------------------------
You might want to reread the section on binary searches in ordered arrays in Chapter
2, which describes how this method works. Also, run the Ordered Workshop applet from that chapter if you want to see a binary search in action.
We can transform this loop-based method into a recursive method quite easily. In the loop-based method, we change lowerBound or upperBound to specify a new range and then cycle through the loop again. Each time through the loop we divide the range (roughly) in half.
Recursion Replaces the Loop
In the recursive approach, instead of changing lowerBound or upperBound , we call
A Recursive Binary Search 269
private int recFind(long searchKey, int lowerBound,
int upperBound)
{ int curIn;
curIn = (lowerBound + upperBound ) / 2; if(a[curIn]==searchKey)
return curIn; // found it else if(lowerBound > upperBound) return nElems; // can’t find it else // divide range { if(a[curIn] < searchKey) // it’s in upper half
return recFind(searchKey, curIn+1, upperBound); else // it’s in lower half return recFind(searchKey, lowerBound, curIn-1); } // end else divide range } // end recFind()
The class user, represented by main() , may not know how many items are in the array when it calls find() , and in any case shouldn’t be burdened with having to know what values of upperBound and lowerBound to set initially. Therefore, we supply an intermediate public method, find() , which main() calls with only one argument, the value of the search key. The find() method supplies the proper initial values of lowerBound and upperBound (0 and nElems-1 ) and then calls the private, recursive method recFind() . The find() method looks like this:
public int find(long searchKey) { return recFind(searchKey, 0, nElems-1); }
Listing 6.3 shows the complete listing for the binarySearch.java program. LISTING 6.3 The binarySearch.java Program
// binarySearch.java // demonstrates recursive binary search // to run this program: C>java BinarySearchApp //////////////////////////////////////////////////////////////// class ordArray
{ private long[] a; // ref to array a
270 CHAPTER 6 Recursion
LISTING 6.3 Continued private int nElems; // number of data items
//----------------------------------------------------------- public ordArray(int max) // constructor
{ a = new long[max]; // create array nElems = 0; }
//----------------------------------------------------------- public int size()
{ return nElems; } //----------------------------------------------------------- public int find(long searchKey)
{ return recFind(searchKey, 0, nElems-1); }
//----------------------------------------------------------- private int recFind(long searchKey, int lowerBound,
int upperBound) { int curIn;
curIn = (lowerBound + upperBound ) / 2; if(a[curIn]==searchKey)
return curIn; // found it else if(lowerBound > upperBound) return nElems; // can’t find it else // divide range { if(a[curIn] < searchKey) // it’s in upper half
return recFind(searchKey, curIn+1, upperBound); else // it’s in lower half return recFind(searchKey, lowerBound, curIn-1); } // end else divide range } // end recFind() //----------------------------------------------------------- public void insert(long value) // put element into array
{ int j; for(j=0; j<nElems; j++) // find where it goes
if(a[j] > value) // (linear search)
break;
A Recursive Binary Search 271
LISTING 6.3 Continued for(int k=nElems; k>j; k--) // move bigger ones up
a[k] = a[k-1]; a[j] = value; // insert it nElems++; // increment size } // end insert()
//----------------------------------------------------------- public void display() // displays array contents
{ for(int j=0; j<nElems; j++) // for each element,
System.out.print(a[j] + “ “); // display it System.out.println(“”); }
//----------------------------------------------------------- } // end class ordArray
//////////////////////////////////////////////////////////////// class BinarySearchApp
{ public static void main(String[] args)
{ int maxSize = 100; // array size ordArray arr; // reference to array arr = new ordArray(maxSize); // create the array
arr.insert(72); // insert items arr.insert(90); arr.insert(45); arr.insert(126); arr.insert(54); arr.insert(99); arr.insert(144); arr.insert(27); arr.insert(135); arr.insert(81); arr.insert(18); arr.insert(108); arr.insert(9); arr.insert(117); arr.insert(63); arr.insert(36);
272 CHAPTER 6 Recursion
LISTING 6.3 Continued arr.display(); // display array
int searchKey = 27; // search for item if( arr.find(searchKey) != arr.size() )
System.out.println(“Found “ + searchKey); else System.out.println(“Can’t find “ + searchKey); } // end main() } // end class BinarySearchApp ////////////////////////////////////////////////////////////////
In main() we insert 16 items into the array. The insert() method arranges them in sorted order; they’re then displayed. Finally, we use find() to try to find the item
with a key value of 27. Here’s some sample output: 9 18 27 36 45 54 63 72 81 90 99 108 117 126 135 144
Found 27 In binarySearch.java there are 16 items in an array. Figure 6.9 shows how the
recFind() method in this program calls itself over and over, each time with a smaller range than before. When the innermost version of the method finds the desired item, which has the key value 27, it returns with the index value of the item, which is 2 (as can be seen in the display of ordered data). This value is then returned from each version of recFind() in turn; finally, find() returns it to the class user.
The recursive binary search has the same big O efficiency as the non-recursive version: O(logN). It is somewhat more elegant, but may be slightly slower.