Рубрики
Без рубрики

Алгоритмы поиска объяснены примерами в Java, Python и C ++

Автор оригинала: FreeCodeCapm Team.

Что такое алгоритм поиска?

Этот вид алгоритма смотрит на проблему повторно распознавания массива предметов в порядке возрастания. Два самых классических примера это является двоичным поиском и алгоритм сортировки слияния.

Экспоненциальный поиск

Экспоненциальный поиск, также известный как поиск пальца, поиск элемента в отсортированном массиве, прыжки 2 ^ Я Элементы в каждой итерации, где я представляет значение переменной управления петли, а затем проверяя, если элемент поиска присутствует между последним прыжками и ток.

Сложность худшего случая

O (log (n)) часто запутался из-за имени, алгоритм назван так не из-за сложности времени. Имя возникает в результате алгоритма, скачающих элементы с шагами, равными показателям из 2

Шаги

  1. Прыгать на массив 2 ^ Я Элементы во время поиска состояния Массив [2 ^ (I-1)] Отказ Если 2 ^ Я больше, чем длина массива, затем установить верхнюю часть на длину массива.
  2. Делайте двоичный поиск между Массив [2 ^ (I-1)] и Массив [2 ^ I]
// C++ program to find an element x in a
// sorted array using Exponential search.
#include 
using namespace std;
 
int binarySearch(int arr[], int, int, int);
 
// Returns position of first ocurrence of
// x in array
int exponentialSearch(int arr[], int n, int x)
{
    // If x is present at firt location itself
    if (arr[0] == x)
        return 0;
 
    // Find range for binary search by
    // repeated doubling
    int i = 1;
    while (i < n && arr[i] <= x)
        i = i*2;
 
    //  Call binary search for the found range.
    return binarySearch(arr, i/2, min(i, n), x);
}
 
// A recursive binary search function. It returns
// location of x in  given array arr[l..r] is
// present, otherwise -1
int binarySearch(int arr[], int l, int r, int x)
{
    if (r >= l)
    {
        int mid = l + (r - l)/2;
 
        // If the element is present at the middle
        // itself
        if (arr[mid] == x)
            return mid;
 
        // If element is smaller than mid, then it
        // can only be present n left subarray
        if (arr[mid] > x)
            return binarySearch(arr, l, mid-1, x);
 
        // Else the element can only be present
        // in right subarray
        return binarySearch(arr, mid+1, r, x);
    }
 
    // We reach here when element is not present
    // in array
    return -1;
}
 
int main(void)
{
   int arr[] = {2, 3, 4, 10, 40};
   int n = sizeof(arr)/ sizeof(arr[0]);
   int x = 10;
   int result = exponentialSearch(arr, n, x);
   (result == -1)? printf("Element is not present in array")
                 : printf("Element is present at index %d", result);
   return 0;
}

Поиск связанных списков против массивов

Предположим, вы должны искать элемент в несортированный Связанный список и массив. В этом случае вам нужно сделать линейный поиск (запомнить, несортировать). Выполнение линейного поиска элемента в любой структуре данных будет работать операция O (N).

Теперь, если у вас есть отсортировано Связанный список и массив, вы все равно можете искать как в структурах данных в O (log n), используя двоичные поиск. Хотя это будет немного утомительным для кода при использовании связанных списков.

Связанные списки обычно предпочтительны над массивами, где вставка является частой операцией. Легче вставлять в связанные списки как только изменения указателя. Но вставить в массив (середине или начало), вам нужно перемещать все элементы после того, как вы вставляете. Другое место, где вы должны использовать связанные списки, – это то, где размер неясно (вы не знаете размер, когда вы начинаете), потому что массивы имеют фиксированный размер.

Массивы обеспечивают несколько преимуществ по поводу связанных списков:

  1. Случайный доступ
  2. Меньше памяти по сравнению с связанными списками
  3. Массивы имеют лучшую местность кэша, таким образом, обеспечивая лучшую производительность

Это полностью зависит от случая использования для того, лучше ли массивы или связанные списки.

Линейный поиск

Предположим, вам дан список или массив предметов. Вы ищете конкретный товар. Как ты это делаешь?

Найдите номер 13 в данном списке.

Вы просто смотрите в список и там есть!

Теперь, как вы говорите компьютеру, чтобы найти его.

Компьютер не может выглядеть больше, чем значение в данном мгновенном времени. Таким образом, он принимает один элемент из массива и проверяет, является ли оно то же самое, что вы ищете.

Первый предмет не совпадал. Так двигайся на следующий.

И так далее…

Это сделано до тех пор, пока совпадение не найдено или пока все элементы не будут проверены.

В этом алгоритме вы можете остановиться, когда товар найден, а затем нет необходимости смотреть дальше.

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

Следовательно, сложность линейного поиска является O (n).

Если элемент будет искать, председают на первом блоке памяти, то сложность будет o (1).

Код для функции линейного поиска в JavaScript показан ниже. Эта функция возвращает положение элемента, которую мы ищем в массиве. Если элемент не присутствует в массиве, функция вернет нулю.

int linearSearch(int arr[], int num)
{
        int len = (int)( sizeof(arr) / sizeof(arr[0]);
        int *a = arr;
        for(int i = 0; i < len; i++)
        {
                if(*(a+i) == num) return i;
        }
        return -1;
}

Пример в JavaScript

function linearSearch(arr, item) {
  // Go through all the elements of arr to look for item.
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] === item) { // Found it!
      return i;
    }
  }
  
  // Item not found in the array.
  return null;
}

Пример в Рубина

def linear_search(target, array)
  counter = 0

  while counter < array.length
    if array[counter] == target
      return counter
    else
      counter += 1
    end
  end
  return nil
end

Пример в C ++

int linear_search(int arr[],int n,int num)
{
	for(int i=0;i

Пример в Python

def linear_search(array, num):
	for index, element in enumerate(array):
		if element == num:
			return index
	return -1

Пример в Swift

func linearSearch(for number: Int, in array: [Int]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == number { return index } // return the index of the number
    }
    return nil // the number was not found in the array
}

Пример в Java

int linearSearch(int[] arr, int element)
{
        for(int i=0;i

Пример в PHP.

function linear_search($arr=[],$num=0)
{
     $n = count($arr);   
     for( $i=0; $i<$n; $i++){
           if($arr[$i] == $num)
                return $i;
      }
      // Item not found in the array
      return -1; 
}

$arr = array(1,3,2,8,5,7,4,0);
print("Linear search result for 2: ");
echo linear_search($arr,2);

Глобальный линейный поиск

Что, если вы ищете несколько вхождений элемента? Например, вы хотите увидеть, сколько 5 находятся в массиве.

Цель

Массив = [1, 2, 3, 4, 5, 6, 5, 7, 8, 9, 5]

Этот массив имеет 3 происшествия 5s, и мы хотим вернуть индексы (где они находятся в массиве) всех. Это называется глобальным линейным поиском. Вам нужно будет настроить свой код, чтобы вернуть массив точек индекса, на которых он находит целевой элемент. Когда вы найдете элемент индекса, который соответствует вашу цель, указательная точка (счетчик) будет добавлена в массиве результатов. Если он не соответствует, код продолжит переходить к следующему элементу в массиве, добавив 1 на счетчик.

def global_linear_search(target, array)
  counter = 0
  results = []

  while counter < array.length
    if array[counter] == target
      results << counter
      counter += 1
    else
      counter += 1
    end
  end

  if results.empty?
    return nil
  else
    return results
  end
end

Почему линейный поиск не эффективен

Нет сомнений в том, что линейный поиск прост, но потому что он сравнивает каждый элемент один за другим, оно поглощает и, следовательно, не очень эффективно. Если мы должны найти номер, скажем, 1000000 номеров и номер в последнем месте, метод линейного поиска станет довольно утомительным. Итак, также узнайте о двоичных поисковых, экспоненциальных поисках и т. Д., которые намного эффективнее, чем линейный поиск.

Бинарный поиск

Двоичный поиск находит элемент в отсортированном массиве, неоднократно разделяя интервал поиска пополам.

Как вы ищете имя в телефонном справочнике?

Один из способов начать с первой страницы и посмотреть на каждое имя в телефонной книге, пока не найдем то, что мы ищем. Но это было бы чрезвычайно трудоемким и неэффективным способом поиска.

Поскольку мы знаем, что имена в телефонной книге сортируются в алфавитном порядке, мы, вероятно, могли работать по следующим этапам:

  1. Откройте среднюю страницу телефонной книги
  2. Если у него есть имя, которое мы ищем, мы сделаем!
  3. В противном случае выбросить половину телефонной книги, которая не содержит имени
  4. Повторить, пока не найдешь имя или нет больше страниц, оставшихся в телефонной книге

[

]

Сложность времени: поскольку мы утилизируем одну часть вида поиска во время каждого шага двоичного поиска и выполнять операцию поиска, а это приводит к тому, что в худшем случае сложности в худшем случае O ( log2n ). Лучший случай возникает, когда элемент найден находится в середине списка. Лучший случай Сложность времени – O ( 1 ).

Космическая сложность: двоичный поиск принимает постоянное или O ( 1 ) Пространство означает, что мы не делаем никаких изменений, связанных с размером ввода.

Для небольших комплектов линейный поиск лучше, но в более крупных он способен эффективнее использовать двоичный поиск.

Подробно, сколько раз вы можете разделить N на 2, пока у вас не будет 1? Это, по сути, скажем, делают двоичный поиск (половина элементов), пока вы не нашли его. В формуле это было бы это:

1 = N / 2^x

Умножьте на 2 раза:

2^x = N

Теперь сделайте log2:

log2(2^x)   = log2 N
x * log2(2) = log2 N
x * 1       = log2 N

Это означает, что вы можете разделить журнал N раз, пока у вас будет все разделено. Это означает, что вы должны разделить журнал N («выполните шаг двоичного поиска»), пока вы не нашли свой элемент.

O ( log2n ) такой, поэтому на каждом шаге половина элементов в наборе данных исчезло, что оправдано основой логарифмической функции.

Это двоичный алгоритм поиска. Это элегантно и эффективно, но для него правильно работает, массив должен быть отсортировано Отказ

Найдите 5 в данном массиве чисел, использующих двоичный поиск.

Марка низких, высоких и средних позиций в массиве.

Сравните товар, который вы ищете с средним элементом.

Выбросить левую половину и посмотрите в правой половине.

Опять сравните со средним элементом.

Теперь перейдите на левую половину.

Средний элемент – это предмет, который мы искали!

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

Два базовых случая для рекурсии будут:

  • Больше не осталось элементов в массиве
  • Пункт найден

Мощность бинарных поисков в системах данных (b + деревьев): двоичные поисковые деревья очень мощные из-за времени поиска поиска O (log n), второе в структуру данных hashmap, которая использует ключ HASHING, для поиска данных в O (1) Отказ Важно понимать, как время выполнения журнала N поступает от высоты двоичного дерева поиска. Если каждый узел расщепляется на два узла, (двоичные), затем глубина дерева является журналом N (основание 2). Для улучшения этой скорости в системе данных мы используем B + деревья, потому что они имеют больший фактор ветвления, и Поэтому более высота. Я надеюсь, что эта короткая статья помогает расширить ваш разум о том, как бинарный поиск используется в практических системах.

Код для рекурсивного двоичного поиска показан ниже:

Реализация JavaScript

function binarySearch(arr, item, low, high) {
    if (low > high) { // No more elements in the array.
        return null;
    }

    // Find the middle of the array.
    var mid = Math.ceil((low + high) / 2);

    if (arr[mid] === item) { // Found the item!
        return mid;
    }

    if (item < arr[mid]) { // Item is in the half from low to mid-1.
        return binarySearch(arr, item, low, mid-1);
    }

    else { // Item is in the half from mid+1 to high.
        return binarySearch(arr, item, mid+1, high);
    }
}

var numbers = [1,2,3,4,5,6,7];
print(binarySearch(numbers, 5, 0, numbers.length-1));

Вот еще одна реализация в JavaScript:

function binary_search(a, v) {
    function search(low, high) {
        if (low === high) {
            return a[low] === v;
        } else {
            var mid = math_floor((low + high) / 2);
            return (v === a[mid])
                   ||
                   (v < a[mid])
                   ? search(low, mid - 1)
                   : search(mid + 1, high);
        }
    }
    return search(0, array_length(a) - 1);
}

Реализация Ruby

def binary_search(target, array)
  sorted_array = array.sort
  low = 0
  high = (sorted_array.length) - 1

  while high >= low
    middle = (low + high) / 2

    if target > sorted_array[middle]
      low = middle + 1
    elsif target < sorted_array[middle]
      high = middle - 1
    else
      return middle
    end
  end
  return nil
end

Пример в C.

int binarySearch(int a[], int l, int r, int x) {
   if (r >= l){
        int mid = (l + (r - l))/2;
        if (a[mid] == x)
            return mid;
        if (arr[mid] > x)
            return binarySearch(arr, l, mid-1, x);
        return binarySearch(arr, mid+1, r, x);
   }
   return -1;
}

Реализация Python

def binary_search(arr, l, r, target):
    if r >= l:
        mid = (l + (r - l))/2
        if arr[mid] == target:
            return mid
        elif arr[mid] > target:
            return binary_search(arr, l, mid-1, target)
        else:
            return binary_search(arr, mid+1, r, target)
    else:
        return -1

Пример в C ++

Рекурсивный подход!

// Recursive approach in C++
int binarySearch(int arr[], int start, int end, int x)
{
   if (end >= start)
   {
        int mid = (start + (end - start))/2;
        if (arr[mid] == x)
            return mid;

        if (arr[mid] > x)
            return binarySearch(arr, start, mid-1, x);

        return binarySearch(arr, mid+1, end, x);
   }
   return -1;
}

Итеративный подход!

int binarySearch(int arr[], int start, int end, int x)
{
    while (start <= end)
    {
        int mid = (start + (end - start))/2;
        if (arr[mid] == x)
            return mid;
        if (arr[mid] < x)
            start = mid + 1;
        else
            end = mid - 1;
    }
    return -1;
}

Пример в Swift

func binarySearch(for number: Int, in numbers: [Int]) -> Int? {
    var lowerBound = 0
    var upperBound = numbers.count
    while lowerBound < upperBound {
        let index = lowerBound + (upperBound - lowerBound) / 2
        if numbers[index] == number {
            return index // we found the given number at this index
        } else if numbers[index] < number {
            lowerBound = index + 1
        } else {
            upperBound = index
        }
    }
    return nil // the given number was not found
}

Пример в Java

// Iterative Approach in Java
int binarySearch(int[] arr, int start, int end, int element)
{
    while(start <= end)
    {
        int mid = start + ( end - start ) / 2;
        if(arr[mid] == element)
            return mid;
        if(arr[mid] < element)
            start = mid+1;
        else
            end = mid-1;
    }
   return -1;
}
// Recursive Approach in Java
int binarySearch(int[] arr, int start,int end , int element)
{
  if (end >= start)
  {
    int mid = start + ( end - start ) / 2;
    if(arr[mid] ==  element)
        return mid;
    if(arr[mid] < element)
        return binarySearch( arr , mid + 1 , end , element );
    else
        return binarySearch( arr, start, mid - 1 , element);
  }
  return -1;
}