Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Рацеев С.М. Программирование на языке Си.pdf
Скачиваний:
369
Добавлен:
23.03.2016
Размер:
1.65 Mб
Скачать

Приложение 1. АЛГОРИТМЫ ПОИСКА

Пусть имеется некоторый массив a (например, действительных чисел) размером n. Нужно определить, содержит ли массив a элемент с некоторым наперед заданным значением x. Если ответ положительный, то требуется возвратить индекс элемента со значением x, в противном случае – возвратить значение -1. В данном разделе приведены три алгоритма решения данной задачи: линейный поиск, поиск с барьером и двоичный поиск.

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

Алгоритм линейного поиска заключается в том, что массив последовательно просматривается по одному элементу до тех пор, пока либо не встретится искомый элемент x, либо не будут просмотрены все элементы массива (если элемента x в массиве нет).

int LinearSearch(const double *a, const int n, const double x)

{

int i; i = -1;

while (++i < n && a[i] != x)

;

return (i < n) ? i : -1;

}

2. Поиск с барьером

Алгоритм линейного поиска можно немного усовершенствовать, если в цикле while убрать проверку выхода за границу массива (i < n). Но для этого надо иметь гарантию, что элемент x обязательно найдется в массиве a, чтобы цикл while остановился. Для этой цели в конец массива достаточно поместить дополнительный

298

элемент со значением x. Такой элемент называется барьерным элементом.

int BarrierSearch(double *a, const int n, const double x)

{

int i;

a[n-1] = x; /* на последнее место ставим барьерный элемент */ i = -1;

while (a[++i] != x)

;

return (i < n-1) ? i : -1;

}

3. Двоичный поиск

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

Пусть l и r – соответственно левая и правая границы того подмассива в массиве a, который предположительно содержит искомый элемент x:

Изначально значения l и r охватывают весь массив a, то есть l=0 и r=n-1, где n – размерность массива a. На очередном шаге находим середину отрезка [l, r]: mid=(l+r)/2. После чего элемент x сравниваем со средним элементом a[mid] текущего подмассива (с границами l и r). При этом возможны такие ситуации: x==a[mid], x<a[mid], x>a[mid]. В первом сл учае элемент x найден в массиве a, и поиск можно завершить. В двух других случаях мы можем отбросить половину текущего подмассива путем переопределения либо значения l, либо значения r. Например, если x<a[mid], то понятно, что интересуемый нас элемент может находиться до элемента с индексом mid, поэтому переопределим значение правой границы r, положив r=mid-1, после чего переходим к следующему шагу.

299

int BinarySearch(const double *a, const int n, const double x)

{

int l,

/* левая граница рассматриваемого массива

*/

r,

/* правая граница рассматриваемого массива */

mid;

/* середина отрезка [l, r]

*/

l = 0;

r = n – 1; while (l < r)

{

mid = (l + r) / 2; /* вычисляем середину отрезка [l, r] */ if (a[mid] == x)

l = r = mid; else

if (a[mid] < x) l = mid + 1;

else r = mid - 1;

}

return (a[l] == x) ? l : -1;

}

300