Как использовать рекурсию при создании алгоритма бинарного поиска
Я использую свое свободное время в университете, чтобы практиковать Java через алгоритмы кодирования. Одним из алгоритмов, которые я закодировал, был двоичный поиск:
public class BinarySearch {
private static int list[] = {3, 6, 7, 8, 9, 10};
public static void main(String[] args) {
BinarySearch b = new BinarySearch();
b.binarySearch(list);
}
public void binarySearch(int[] args) {
System.out.println("Binary search.");
int upperBound = args.length;
int lowerBound = 1;
int midpoint = (upperBound + lowerBound) / 2;
int difference = upperBound - lowerBound;
int search = 7;
for (int i = 0; i < args.length; i++) {
if (search < args[midpoint - 1] && difference != 1) {
upperBound = midpoint - 1;
midpoint = upperBound / 2;
} else if (search > args[midpoint - 1] && difference != 1) {
lowerBound = midpoint + 1;
midpoint = (lowerBound + upperBound) / 2;
} else if (search == args[midpoint - 1]) {
midpoint = midpoint - 1;
System.out.println("We found " + search + " at position " + midpoint + " in the list.");
i = args.length;
} else {
System.out.println("We couldn't find " + search + " in the list.");
i = args.length;
}
}
}
}
Я действительно хочу иметь возможность написать гораздо более чистый и эффективный алгоритм бинарного поиска, альтернативу тому, что я закодировал. Я видел примеры того, как рекурсия используется, например, при выполнении факториала с числами, которые я понимаю. Однако при кодировании чего-то такого сложного я запутался в том, как использовать его для моего преимущество. Поэтому мой вопрос заключается в том, как применять рекурсию при кодировании алгоритма двоичного поиска. И если у вас есть какие-либо советы для меня, чтобы улучшить мои навыки рекурсии, даже если это должно быть что-то, что не относится к двоичному поиску, пожалуйста, не стесняйтесь публиковать.
8 ответов
Если вы действительно хотите использовать рекурсию, это должно помочь.
public static int binarySearch(int[] a, int target) {
return binarySearch(a, 0, a.length-1, target);
}
public static int binarySearch(int[] a, int start, int end, int target) {
int middle = (start + end) / 2;
if(end < start) {
return -1;
}
if(target==a[middle]) {
return middle;
} else if(target<a[middle]) {
return binarySearch(a, start, middle - 1, target);
} else {
return binarySearch(a, middle + 1, end, target);
}
}
вот более простой способ выполнения двоичного поиска:
public static int binarySearch(int intToSearch, int[] sortedArray) {
int lower = 0;
int upper = sortedArray.length - 1;
while (lower <= upper) {
int mid = lower + (upper - lower) / 2;
if(intToSearch < sortedArray[mid])
upper = mid - 1;
else if (intToSearch > sortedArray[mid])
lower = mid + 1;
else
return mid;
}
return -1; // Returns -1 if no match is found
}
Ниже приведен пример кода, извлеченные из здесь.
public class BinarySearch {
public boolean find(int[] sortedValues, int value) {
return search(sortedValues, value, 0, sortedValues.length - 1);
}
private boolean search(int[] sorted, int value, int leftIndex, int rightIndex) {
// 1. index check
if (leftIndex > rightIndex) {
return false;
}
// 2. middle index
int middle = (rightIndex + leftIndex) / 2;
// 3. recursive invoke
if (sorted[middle] > value) {
return search(sorted, value, leftIndex, middle - 1);
} else if (sorted[middle] < value) {
return search(sorted, value, middle + 1, rightIndex);
} else {
return true;
}
}
}
вы можете найти реализации приведенных ниже тестовых случаев против вышеуказанной реализации двоичного поиска, а также в ссылке ссылке.
1. shouldReturnFalseIfArrayIsEmpty()
2. shouldReturnFalseIfNotFoundInSortedOddArray()
3. shouldReturnFalseIfNotFoundInSortedEvenArray()
4. shouldReturnTrueIfFoundAsFirstInSortedArray()
5. shouldReturnTrueIfFoundAtEndInSortedArray()
6. shouldReturnTrueIfFoundInMiddleInSortedArray()
7. shouldReturnTrueIfFoundAnywhereInSortedArray()
8. shouldReturnFalseIfNotFoundInSortedArray()
вот алгоритм, который должен заставить вас идти. Пусть ваша подпись метода будет:
public boolean binarysearchRecursion(Array, begin_index,end_index, search_element)
- проверьте, если ваш begin_index > end_index если да, то return
false
. - вычислить
mid_element
для входного массива. - проверьте, если ваш
search_element
равнаmid_element
. если да, вернитесьtrue
- если
mid_element
>search_element
вызовите свой метод с помощью forrange 0 - mid
- если
mid_element
search_element вызовите свой метод с помощью for rangemid+1 - Length_of_Array
также, как сказал @DwB в своем комментарии, Вам лучше использовать loop для выполнения задач. Некоторые проблемы рекурсивны по своей природе (например, проблемы с двоичным деревом). Но этот не из их числа.
Это еще один способ сделать рекурсию:
int[] n = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
@Test
public void testRecursiveSolution() {
Assert.assertEquals(0, recursiveBinarySearch(1,n));
Assert.assertEquals(15, recursiveBinarySearch(16,n));
Assert.assertEquals(14, recursiveBinarySearch(15,n));
Assert.assertEquals(13, recursiveBinarySearch(14,n));
Assert.assertEquals(12, recursiveBinarySearch(13,n));
Assert.assertEquals(11, recursiveBinarySearch(12,n));
Assert.assertEquals(10, recursiveBinarySearch(11,n));
Assert.assertEquals(9, recursiveBinarySearch(10,n));
Assert.assertEquals(-1, recursiveBinarySearch(100,n));
}
private int recursiveBinarySearch(int n, int[] array) {
if(array.length==1) {
if(array[0]==n) {
return 0;
} else {
return -1;
}
} else {
int mid = (array.length-1)/2;
if(array[mid]==n) {
return mid;
} else if(array[mid]>n) {
return recursiveBinarySearch(n, Arrays.copyOfRange(array, 0, mid));
} else {
int returnIndex = recursiveBinarySearch(n, Arrays.copyOfRange(array, mid+1, array.length));
if(returnIndex>=0) {
return returnIndex+mid+1;
} else {
return returnIndex;
}
}
}
}
возможный пример :
// need extra "helper" method, feed in params
public int binarySearch(int[] a, int x) {
return binarySearch(a, x, 0, a.length - 1);
}
// need extra low and high parameters
private int binarySearch(int[ ] a, int x,
int low, int high) {
if (low > high) return -1;
int mid = (low + high)/2;
if (a[mid] == x) return mid;
else if (a[mid] < x)
return binarySearch(a, x, mid+1, high);
else // last possibility: a[mid] > x
return binarySearch(a, x, low, mid-1);
}
здесь вы можете проверить двоичный поиск C, с рекурсией и без нее
источник:http://www.cs.utsa.edu / ~wagner/CS3343/recursion/binsearch.html
хотя он не возвращает индекс, это, по крайней мере, возвращает идею " да " или "нет", что что-то находится в коллекции:
public static boolean recursive(int[] input, int valueToFind) {
if (input.length == 0) {
return false;
}
int mid = input.length / 2;
if (input[mid] == valueToFind) {
return true;
} else if (input[mid] > valueToFind) {
int[] smallerInput = Arrays.copyOfRange(input, 0, mid);
return recursive(smallerInput, valueToFind);
} else if (input[mid] < valueToFind) {
int[] smallerInput = Arrays.copyOfRange(input, mid+1, input.length);
return recursive(smallerInput, valueToFind);
}
return false;
}
рекурсия BinarySearch с условиями перерыва в случае, если вы не можете найти значение, которое вы ищете
public interface Searcher{
public int search(int [] data, int target, int low, int high);
}
Реализация
public class BinarySearch implements Searcher {
public int search(int[] data, int target, int low, int high) {
//The return variable
int retorno = -1;
if(low > high) return retorno;
int middle = (high + low)/2;
if(target == data[middle]){
retorno = data[middle];
}else if(target < data[middle] && (middle - 1 != high)){
//the (middle - 1 != high) avoids beeing locked inside a never ending recursion loop
retorno = search(data, target, low, middle - 1);
}else if(target > data[middle] && (middle - 1 != low)){
//the (middle - 1 != low) avoids beeing locked inside a never ending recursion loop
retorno = search(data, target, middle - 1, high);
}else if(middle - 1 == low || middle - 1 == high){
//Break condition if you can not find the desired balue
retorno = -1;
}
return retorno;
}
}