-
Notifications
You must be signed in to change notification settings - Fork 4
Recursion Part 2
Anthony Christe edited this page Oct 21, 2013
·
5 revisions
- Dichotomic divide-and-conquer search algorithm
- Search for item in ordered data set
- Can use key/value stores (order by key, each key corresponds to one value (i.e. phone book))
- Halves number of items each iteration of algorithm
- O(log2 N)
The chart below shows how many operations a binary search vs a sequential search performs based on the algorithm type.
| Data Size / Sort Type | Binary Search | Sequential Search |
|---|---|---|
| 10 | 3.3 | 10 |
| 100 | 6.6 | 100 |
| 10,000 | 13.3 | 10,000 |
| 1,000,000 | 19.9 | 1,000,000 |
| 1,000,000,000 | 29.9 | 1,000,000,000 |
public int sequentialSearch(int[] data, int item, int i) {
// Searched entire array, but did not find item
if(i == data.length) {
return -1;
}
// Found the item
if(data[i] == item) {
return i;
}
// Keep searching
return sequentialSearch(data, item, i + 1);
}- The item is not in the data
- The item has been found
- Is the item we're looking for greater than the current middle?
- Is the item we're looking for less than the current middle?
// Public helper method
public int binarySearch(int[] data, int item) {
return binarySearch(data, item, 0, data.length - 1);
}
// Private recursive method
private int binarySearch(int[] data, int item, int low, int high) {
// Find the midpoint
int middle = (low + high) / 2;
// Item is not in data
if(low > high) {
return -1;
}
// Item matches middle
if(data[middle] == item) {
return middle;
}
// Item is less than curent middle
if(item < data[middle]) {
return binarySearch(data, item, low, middle - 1);
}
// Item is greater than current middle
else {
return binarySearch(data, item, middle + 1, high);
}
}// Public helper method
public <T extends Comparable<T>> int binarySearch(T[] data, T item) {
return binarySearch(data, item, 0, data.length - 1);
}
// Private recursive method
private <T extends Comparable<T>> int binarySearch(T[] data, T item, int low, int high) {
// Find the midpoint
int middle = (low + high) / 2;
// Item is not in data
if(low > high) {
return -1;
}
// Item matches middle
if(data[middle].compareTo(item) == 0) {
return middle;
}
// Item is less than curent middle
if(item.compareTo(data[middle]) < 0) {
return binarySearch(data, item, low, middle - 1);
}
// Item is greater than current middle
else {
return binarySearch(data, item, middle + 1, high);
}
}- Many operations for linked lists can be completed using recursion
- Bases cases generally involve determining if we've found a specific node, or if we're reached the end of the list
public E get(int index) {
// Empty list or invalid index
if(this.size == 0 || index < 0 || index >= this.size) {
return new NoSuchElementException();
}
return get(index, 0, this.head);
}
private E get(int index, int currIndex, LinkedNode<E> node) {
// At the given index
if(index == currIndex) {
return node.getData();
}
// Keep advancing
return get(index, currIndex + 1, node.getNext());
}public void indexOf(E item) {
if(this.size == 0) {
return -1;
}
return indexOf(E item, this.head, 0);
}
private void indexOf(E item, LinkedNode<E> node, index) {
// Item not in list
if(node == null) {
return -1;
}
// Found item
if(node.getData().equals(item)) {
return index;
}
// Try the next item
return indexOf(item, node.getNext(), index + 1);
}@Override
public String toString() {
if(this.size == 0) {
return "[]";
}
return "[" + toString(this.head);
}
private String toString(LinkedNode<E> node) {
// Found last node in list
if(node.getNext() == null) {
return node.getData() + "]";
}
// Store this nodes data, and recursively concatenate next node
return node.getData() + "," + toString(node.getNext());
}public void add(E item) {
if(this.size == 0) {
this.head = new LinkedNode<E>(item);
}
else {
add(item, this.head);
}
this.size++;
}
private void add(E item, LinkedNode<E> node) {
// Have we reached the end of the list?
if(node.getNext() == null) {
node.setNext(new LinkedNode<E>(item));
}
else {
add(item, node.getNext());
}
}