Алгоритм двоичного поиска в Java
1. обзор
В этой статье мы рассмотрим преимущества двоичного поиска по сравнению с простым линейным поиском и рассмотрим его реализацию на Java.
2. Необходимость эффективного поиска
Допустим, мы занимаемся продажей вин, и миллионы покупателей посещают наше приложение каждый день.
С помощью нашего приложения покупатель может отфильтровать товары, цена которых нижеn долларов, выбрать бутылку из результатов поиска и добавить их в свою корзину. У нас миллионы пользователей, которые ищут вина с ценовым ограничением каждую секунду. Результаты должны быть быстрыми.
На бэкэнде наш алгоритм выполняет линейный поиск по всему списку вин, сравнивая предельную цену, введенную клиентом, с ценой каждой бутылки вина в списке.
Затем он возвращает элементы, цена которых меньше или равна предельной цене. Этот линейный поиск имеет временную сложностьO(n).
Это означает, что чем больше бутылок вина в нашей системе, тем больше времени это займет. The search time increases proportionately to the number of new items introduced.с
Если мы начнем сохранять элементы в отсортированном порядке и искать элементы с помощью двоичного поиска, мы можем достичь сложностиO(log n).
При двоичном поиске время, затрачиваемое на результаты поиска, естественным образом увеличивается с размером набора данных, но не пропорционально.
3. Бинарный поиск
Проще говоря, алгоритм сравнивает значениеkey со средним элементом массива; если они не равны, половина, в которой ключ не может быть частью, удаляется, и поиск продолжается для оставшейся половины до тех пор, пока не будет успешным.
Помните - ключевым аспектом здесь является то, что массив уже отсортирован.
Если поиск заканчивается, а оставшаяся половина остается пустой,key отсутствует в массиве.
3.1. Итеративный импл
public int runBinarySearchIteratively(
int[] sortedArray, int key, int low, int high) {
int index = Integer.MAX_VALUE;
while (low <= high) {
int mid = (low + high) / 2;
if (sortedArray[mid] < key) {
low = mid + 1;
} else if (sortedArray[mid] > key) {
high = mid - 1;
} else if (sortedArray[mid] == key) {
index = mid;
break;
}
}
return index;
}
МетодrunBinarySearchIteratively принимает в качестве аргументов индексыsortedArray,key иlow &highsortedArray. Когда метод запускается в первый раз,low, первый индексsortedArray, равен 0, аhigh, последний индексsortedArray, равен его длина - 1.
middle - средний индексsortedArray. Теперь алгоритм запускает циклwhile, сравниваяkey со значением массива среднего индексаsortedArray.
3.2. Рекурсивный Impl
Теперь давайте посмотрим на простую рекурсивную реализацию:
public int runBinarySearchRecursively(
int[] sortedArray, int key, int low, int high) {
int middle = (low + high) / 2;
if (high < low) {
return -1;
}
if (key == sortedArray[middle]) {
return middle;
} else if (key < sortedArray[middle]) {
return runBinarySearchRecursively(
sortedArray, key, low, middle - 1);
} else {
return runBinarySearchRecursively(
sortedArray, key, middle + 1, high);
}
}
МетодrunBinarySearchRecursively принимаетsortedArray,key,, индексыlow иhigh дляsortedArray.
3.3. ИспользуяArrays.binarySearch()
int index = Arrays.binarySearch(sortedArray, key);
A sortedArray иintkey, который должен быть найден в массиве целых чисел, передаются в качестве аргументов методуbinarySearch классаArrays Java. .
3.4. ИспользуяCollections.binarySearch()
int index = Collections.binarySearch(sortedList, key);
A sortedList иIntegerkey, который должен быть найден в списке объектовInteger, передаются в качестве аргументов методуbinarySearch JavaCollections класс.
3.5. Спектакль
Whether to use a recursive or an iterative approach for writing the algorithm is mostly a matter of personal preference. Но все же вот несколько моментов, о которых следует помнить:
1. Рекурсия может быть медленнее из-за накладных расходов на поддержаниеstack и обычно занимает больше памяти 2. Рекурсия не удобна дляstack-. Это может вызватьStackOverflowException при обработке больших наборов данных 3. Рекурсия вносит ясность в код, поскольку делает его короче по сравнению с итеративным подходом
В идеале, бинарный поиск будет выполнять меньшее количество сравнений в отличие от линейного поиска для больших значений n. Для меньших значений n линейный поиск может работать лучше, чем двоичный поиск.
Следует знать, что этот анализ является теоретическим и может варьироваться в зависимости от контекста.
Такжеthe binary search algorithm needs a sorted data set which has its costs too. Если мы используем алгоритм сортировки слиянием для сортировки данных, к нашему коду добавляется дополнительная сложностьn log n.
Поэтому сначала нам нужно хорошо проанализировать наши требования, а затем принять решение о том, какой алгоритм поиска лучше всего соответствует нашим требованиям.
4. Заключение
В этом руководстве демонстрируется реализация алгоритма бинарного поиска и сценарий, в котором предпочтительнее использовать его вместо линейного поиска.
Пожалуйста, найдите код для руководстваover on GitHub.