Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
практичні алгоритмізація дл студ.docx
Скачиваний:
0
Добавлен:
05.01.2020
Размер:
6.12 Mб
Скачать

Пошук в масивах

Програмістові часто доводиться працювати з великими об'ємами даних, що зберігаються в масивах. Може виявитися необхідним визначити, чи містить масив елемент, відповідний деякому ключовому значенню. Процес знаходження певного елементу масиву називається пошуком. У цьому розділі ми обговоримо два методи пошуку - простий метод лінійного пошуку (чи послідовного перебору) і ефективніший метод двійкового пошуку. У вправах 6.34 і 6.35 у кінці цієї глави вам буде запропоновано реалізувати версії лінійного і двійкового пошуку за допомогою рекурсії.

При лінійному пошуку програма, що нижче, відбувається порівняння кожного елементу масиву з ключем пошуку. Оскільки масив не впорядкований особливим чином, вірогідність знаходження необхідного значення в першому і в останньому елементах масиву однакова. Таким чином, в середньому програма повинна буде порівняти ключ пошуку з половиною елементів масиву.

Метод лінійного пошуку добре працює для невеликих або несортованих масивів. Проте для великих масивів він неефективний. У разі сортованого масиву може бути використаний високошвидкісний метод двійкового пошуку.

При двійковому алгоритмі пошуку після кожного порівняння виключається половина елементів масиву, в якому проводиться пошук. Алгоритм знаходить середній елемент масиву і порівнює його з ключем пошуку. Якщо вони рівні, ключ пошуку вважається знайденим і повертається індекс цього елементу. Якщо вони не рівні, завдання спрощується до пошуку в одній половині масиву.

Якщо ключ пошуку менше середнього елементу масиву, пошук здійснюється в першій половині масиву, інакше пошук здійснюється в другій половині. Якщо ключ пошуку у вказаному підмасиві (частини первинного масиву) не знайдений, алгоритм повторюється для чверті масиву. Пошук триває до тих пір, поки ключ не виявиться дорівнює середньому елементу підмасиву або доки підмасив не складатиметься з одного елементу, не рівного ключу (це означає, що ключ пошуку не знайдений).

1. Напишіть дану програму, проаналізуйте її. Змініть значення SIZE 100 на свій номер по списку.

/*Послідовний перебір масиву*/

#include <stdio.h>

#define SIZE 100

int linearSearch (int [], int, int);

main ()

{

int a [SIZE], x, searchKey, element;

for (x = 0; x <- SIZE - 1; x+ + ) /'* породжує якісь дані */

a [ x ] = 2 * x ;

printf("Enter integer search key:\n");

scanf("%d", &searchKey};

element = int linearSearch(a, searchKey, SIZE);

if (element != - 1)

printf("Found value in element %d\n", element);

else

printf("Value not found\n");

return 0;

} .

int linearSearch(int array[], int key, int size)

{

int n;

for (n =0; n <= size - 1; n++)

if (array[n] == key)

return n;

return - 1

}

Enter integer search key:

36

Found value in element 18

Enter integer search key:

37

Value not found

Послідовний перебір масиву

У найгіршому випадку двійковий пошук в масиві з 1024 елементів зажадає тільки 10 порівнянь. Послідовне ділення 1024 на 2 дає значення 512, 256, 128, 64, 32, 16, 8, 4, 2 і 1. Число 1024 (210) до набуття значення, рівного 1, ділиться на 2 тільки десять разів. Ділення на 2 відповідає одному порівнянню в алгоритмі двійкового пошуку. Щоб знайти ключ в масиві з 1048576 (220) елементів, буде потрібно максимум 20 порівнянь. У масиві iз мільярда елементів буде потрібно максимум 30 порівнянь. Це є величезним збільшенням ефективності порівняно з послідовним перебором, який вимагає в середньому порівняння ключа пошуку з половиною елементів масиву. Для масиву з мільярда елементів різниця між 500 мільйонами порівнянь (в середньому) і максимум 30 порівняннями очевидна! Максимальне число порівнянь для будь-якого масиву можна визначити шляхом знаходження першого ступеня 2, що перевершує число елементів в масиві.

Програма, що нижче представлена ітеративна версія функції binarySearch. Функція приймає чотири параметри - цілочисельний масив Ь, цілочисельну змінну searchKey, індекс масиву low і індекс масиву high. Якщо ключ пошуку не відповідає середньому елементу підмасиву, один з індексів low або high змінюється так, щоб пошук можна було проводити в меншому підмасиві. Якщо ключ менше середнього елементу, індексу high привласнюється значення middle - 1 і пошук триває для елементів від low до middle - 1. Якщо ключ більше середнього елементу, індексу low привласнюється значення middle + 1 і пошук триває для елементів від middle + 1 до high. У програмі використовується масив з 15 елементів. Перший ступінь 2, що перевершує число елементів в цьому масиві, рівна 16 (24), тому для знаходження ключа буде потрібно максимум 4 порівняння. У програмі використовуються функції printHeader для виведення індексів масиву і printRow для виведення кожного підмасиву, що виникає в процесі двійкового пошуку. Середній елемент в кожному підмасиві відмічений зірочкою (*), що вказує на елемент, з яким порівнюється ключ пошуку.

2. Напишіть дану програму, проаналізуйте її. Змініть значення SIZE 15 на свій номер по списку.

/*Двійковий пошук в масиві*/

#include <stdio.h>

#define SIZE 15

int binarySearch (int [], int, int, int);

void printHeader(void);

void printRow (int [], int, int, int);

main ()

{

int a[SIZE], i, key, result;

for (i = 0; i <= SIZE - 1; i++)

a [ i ] = 2 * i ;

printf("Enter a number between 0 and 28: ");

scanf("%d", &key);

printHeader();

result = binarySearch(a, key, 0, SIZE - 1);

if (result != - 1)

printf("\n%d found in array element %d\n", key, result);

else

printf("\n%d not found\n", key);

return 0;

}

int binarySearch (int b[], int searchKey, int low, int high)

{

int middle;

while (low <= high){

middle = (low + high) / 2;

printRow(b, low, middle, high);

if (searchKey == b[middle])

return middle;

else if (searchKey < b[middle])

high = middle - 1;

else

low = middle + 1;

}

return - 1; /* ключ пошуку не знайдений */

}

/* Друкує заголовок для даних */

void printHeader(void),

{

int i;

printf("\nSubscripts: \ n");

for (i = 0; i <= SIZE - 1; i++)

printf("%3d ", i);

printf("\n");

for (i = 1; i <= 4 * SIZE; i++)

printf ( "- " );

printf("\n");

}

/* Виводить рядок даних, що показують частину масиву,

що обробляється нині. */

void printRow (.int b[], int low, int mid, int high)

{

int i;

for (i = 0; i <= SIZE - 1; i++)

if (i < low || i > high)

printf ( " " );

else if (i == mid)

printf("%3d*", b[i]); /* відмічає середнє значення */

else

printf("%3d ", b[i]);

printf("\n");

}

Enter a number between 0 and 28: 25

Subscripts:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

0 2 4 6 8 10 12 14* 16 18 20 22 24 26 28

16 18 20 22* 24 26 28

24 26* 28

24*

25 not found

Enter a number between 0 and 28: 8

Subscripts:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

0 2 4 6 8 10 12 14* 16 18 20 22 24 26 28

0 2 4 6* 8 10 12

8 10* 12

8*

8 found in array element 4

Enter a number between 0 and 28: 6

Subscripts:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

0 2 4 6 8 10 12 14* 16 18 20 22 24 26 28

0 2 4 6* 8 10 12

Про 2 4 6 8 10 12

6 found in array element 3