Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
О.О.П / ооп / 4_кол / К курсовой / Методи побудови алгоритмів та їх аналіз / Інформатика_1 (методи побудови алгоритмівта та їх аналіз).doc
Скачиваний:
0
Добавлен:
30.05.2020
Размер:
2.5 Mб
Скачать

Бінарний пошук Пошук діленням навпіл

Кожен із вас мав нагоду шукати деяку інформацію у зви-чайній книжці чи в словнику. Різниця такого пошуку досить очевидна: у словнику вона впорядкована за алфавітом, а в книжці розташована в довільному порядку. Зрозуміло, що пер­ший випадок розміщення інформації набагато зручніший. Як можна скористатися впорядкованістю інформації? Прига-даємо, як ми здійснюємо пошук у словнику:

1) відкриваємо словник у довільному місці й дивимося: якщо шукане слово знайдено, то пошук припиняемо, в іншому випадку переходимо до наступного пункту;

  1. якщо слово знаходиться попереду, то друга частина слов­ника нас уже не цікавить і ми відкриваємо його десь усередині першої частини і починаемо пошук так само, як і в пункті 1);

  2. якщо слово знаходиться далі, то перша частина словника нас не цікавить і ми відкриваємо його десь усередині другої частини та починаемо пошук так само, як і в пункті 1).

Ми, фактично, записали алгоритм пошуку інформації в упо-рядкованій послідовності елементів. Він носить назву бінарно-го (двійкового) пошуку, або пошуку методом поділу навпіл.

Визначимося щодо нашої задачі в алгоритмічних термінах. Нам задано масив а(, і - 1, 2, ..., п, для елементів якого справджується умова: at < a, + 1, і - 1, 2, .... п - 1. Шуканий елемент позначимо х, а елемент масиву, відносно якого масив ділиться на дві частини, - через а\т].

110

Тепер алгоритм бінарного пошуку виглядатиме так:

  1. Визначимо т.

  2. Якщо а[т] = х, то пошук завершено і переходимо до п. 5, в іншому випадку переходимо до п. 3.

  3. Якщо а[т] < х, то всі елементи з індексами, меншими за т, можна відкинути і перейти до п. 1.

  4. Якщо а[т] > х, то всі елементи з індексами, більшими за т, можна відкинути і перейти до п. 1.

  5. Вивести результат (фп].

Нам необхідно однозначно визначитися щодо елемента, від-носно якого відбувається поділ масиву на дві частини. Таким елементом може бути довільний елемент масиву, навіть визна-чений випадковим чином у проміжку [1; N]. Але зрозуміло, що наикращим варіантом буде вибір «центрального» елемента a[N + 1 div 2], оскільки при цьому в будь-якому разі буде від-кидатися половина масиву.

Ще однією домовленістю повинна бути визначеність щодо обставини «відкидання» правої чи лівої частини масиву. Щоце означав? Якщо на самому початку межами масиву є індекси 1 i N, то з кожним кроком цей проміжок звужується. При цьому або значения лівої межі переміщається вправо, або пра­во! - вліво. Для того щоб бути однозначними також і в позна-ченні меж проміжку значень індексів елементів масиву, що розглядається, давайте ліву межу будемо позначати змінною L, а праву - R. У цих термінах «відкидання» лівої частини маси­ву відносно <i[N + 1 div 2] буде відповідати дії' L := (N + 1 div 2) + 1, правої - R := (N + 1 div 2) - 1.

Перш ніж переходити до створення алгоритму, поміркуємо ще над умовами його завершения, тобто над ознаками визна-чення результату пошуку. На кожному кроці ми визначаємо центральний елемент послідовності, відповідно до значения якого відбувається порівняння із шуканим елементом х. Тому, якщо значения шуканого елемента співпаде зі значениям елемента а[т], алгоритм пошуку можна припиняти. Для пе-ревірки цієї умови введемо логічну змінну flag, яка набуватиме значения true у випадку, коли на певному кроці пошуку ми натрапимо на шуканий елемент, тобто виконається умова а[т] = х.

Представимо наведений алгоритм бінарного пошуку мовою Pascal:

L := 1;R:=N; flag := false; while (L <= R) and not flag do begin

m:=(L+R)div2; if a[m] = x then flag := true

111

else if a[m]<x

then L := m + 1 else R := m - 1 end; if flag then writeln ('Шуканий елемент знайдено') else writeln ('Шуканий елемент не знайдено');

Чи не можна дещо вдосконалити цей алгоритм? Виявляеть-ся, можна, помінявши місцями вкладені умовні оператори: пе-ревірку на рівність шуканого елемента і «середнього» вико-нувати в останню чергу, оскільки вона при виконанні нашого алгоритму трапиться лише один раз і приведе до завершения алгоритму. А може статися і така ситуація, що ця умова жод-ного разу не виконається. Перевіряючи умову a[m] = х остан-ньою, ми таким чином запобігаємо зайвим перевіркам умов, які найчастіше не дають позитивного результату:

if a[m]<x then L := m + 1 else if a[m] > x

then R := m - 1

else flag := true;

Можна запропонувати інший варіант цього самого алго­ритму, але з використанням повторения з післяумовою:

L:=1;R:=N; repeat

m:=(L+R)div2; if х > a[m]

then L := m + 1 else if x<a[m]

then R : = m - 1 until (a[m] = x) or (L = R); if a[m] = x then writeln ('Шуканий елемент знайдено')

else writeln ('Шуканий елемент не знайдено');

Суттєвішим удосконаленням алгоритму буде, як і при ліній-ному пошуку, таке, яке передбачило б логічне завершения ал­горитму без зайвої перевірки умови not flag у першому варіанті та a[m] = х у другому. Адже виконання цих умов можливе лише один раз або навіть жодного разу не відбудеться нротягом вико­нання всього алгоритму. I справді, відмова від перевірки збі-гання значения шуканого елемента з поточним значениям ♦ центрального» елемента масиву значно покращуе виграш ефективності алгоритму: на кожному кроці втрати від швидко-го визначення результату виконання алгоритму значно менші, ніж переваги відмови від зайвих порівнянь.

Найефективніший алгоритм бінарного пошуку заданого еле­мента в упорядкованій послідовності виглядатиме так:

112

L:=1;R:=N; while (L<R) do begin

m:=(L + R)div2; if a[m] < x then L := m + 1 else R := m end; if a[R] = x then writeln ('Шуканий елементзнайдено')

else writeln ('Шуканий елемент не знайдено');

Залишилося лише проаналізувати умову визначення ре­зультату пошуку a[R] = х. Умовою виходу з циклу є L > R. Однак умова L > R ніколи не буде досяжною, оскільки проміжок [L; R] завжди зменшується за умови, що або L := m + 1, або R := т. При цьому завершения алгоритму відбудеться лише за умови L = R. Але зрозуміло, що виконання умови L = R зовсім не свідчить про те, що шуканий елемент знайдено. Це говорить лише про те, що ми зменшували проміжок пошуку в масиві і зійшлися на одному елементі (L = R). Чому саме перевіряється на збігання елемент масиву з індексом R, а не L? Проаналізуємо оператор розгалуження, який використовується для знаходження певного елемента:

if a[m]<x

then L := m + 1 else R := m;

Якщо шуканого елемента в масиві немає, то ми весь час від-кидаємо ліву половину масиву, тим самим просуваючи значен­ия L до R. При цьому значения R не змінюється, тобто зали-шається R = N. Якщо ж шуканий елемент у масиві присутній, то найімовірніше, що протягом виконання алгоритму відбу-валося відкидання як правої, так і лівоїчастин. Тому перевірка на наявність шуканого елемента в масиві зводиться до пере-вірки умови, чи є елемент, на якому ми зійшлися, шуканим: a[R] = х. Якщо ж ця умова не виконується, то це означатиме, що шуканого елемента в масиві немає. Особливим випадком є ситуація, коли шуканий елемент знаходиться на N-му місці в масиві. Але і при цьому знайдемо правильну відповідь.

Оцінкою ефективності виконання алгоритму бінарного по­шуку є значения 0(log2N), оскільки саме стільки порівнянь бу­де виконано в запропонованому алгоритмі. Детально це питан­ия розглядалося при ознайомленні з визначенням оцінки ефек-тивності роботи розроблених алгоритмів у першому розділі.

113

/ Запитання для самоконтролю

  1. Навєдіть алгоритм пошуку необхідної інформації у словнику.

  1. Сформулюйте задачу пошуку заданого елемента в упорядкова­ному масиві.

  1. Запишіть алгоритм бінарного пошуку.

  1. Як визначається «центральний» елемент масиву, з яким відбу-вається порівняння при бінарному пошуку?

  2. Як відбувається «відкидання» правоі та лівої частин масиву при бінарному пошуку?

  3. Запишіть алгоритм і текст Pascal-програми бінарного пошуку інформації, при виконанні якого використовується логічна змінна як ознака завершения алгоритму.

  4. Як можна вдосконалити алгоритм, наведений у попередньому пункті? Обґрунтуйте свою відповідь.

  5. Запишіть найефективніший варіант алгоритму бінарного по­шуку. Обґрунтуйте ефективність окремих фрагментів цього алгоритму.

  6. Проаналізуйте умову завершеності алгоритму, наведеного в попередньому пункті.

10. Якою є оцінка ефективності роботи бінарного пошукового алго­ритму?

Завдання

  1. Реалізувати алгоритм бінарного пошуку заданого елемен­та в упорядкованому масиві, перевіряючи його на збігання з елементом, що мае порядковий номер т мовою Pascal. Визна-чити кількість порівнянь, необхідних для виконання цього ал­горитму.

  2. Реалізувати алгоритм бінарного пошуку заданого елемен­та в упорядкованому масиві, не перевіряючи його на збігання з елементом, що мае порядковий номер т мовою Pascal.

  3. Порівняти виконання алгоритмів щодо кількості викона-них порівнянь у завданнях 1,2, протестувавши їх для випад-ків, коли шуканий елемент розміщений:

  1. на початку масиву;

  2. у кінці масиву;

  3. посередині масиву.

4. Зробити письмовий аналіз завдання 3.

РЕКУРСИВШ ПОШУКОВІ АЛГОРИТМИ