Алгоритм двоичного поиска в Java

Алгоритм двоичного поиска в Java

1. обзор

В этой статье мы рассмотрим преимущества двоичного поиска по сравнению с простым линейным поиском и рассмотрим его реализацию на Java.

Допустим, мы занимаемся продажей вин, и миллионы покупателей посещают наше приложение каждый день.

С помощью нашего приложения покупатель может отфильтровать товары, цена которых нижеn долларов, выбрать бутылку из результатов поиска и добавить их в свою корзину. У нас миллионы пользователей, которые ищут вина с ценовым ограничением каждую секунду. Результаты должны быть быстрыми.

На бэкэнде наш алгоритм выполняет линейный поиск по всему списку вин, сравнивая предельную цену, введенную клиентом, с ценой каждой бутылки вина в списке.

Затем он возвращает элементы, цена которых меньше или равна предельной цене. Этот линейный поиск имеет временную сложностьO(n).

Это означает, что чем больше бутылок вина в нашей системе, тем больше времени это займет. The search time increases proportionately to the number of new items introduced.с

Если мы начнем сохранять элементы в отсортированном порядке и искать элементы с помощью двоичного поиска, мы можем достичь сложностиO(log n).

При двоичном поиске время, затрачиваемое на результаты поиска, естественным образом увеличивается с размером набора данных, но не пропорционально.

Проще говоря, алгоритм сравнивает значение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.