Двійкóвий пóшук — алгоритм знаходження заданого значення у впорядкованому масиві, який полягає у порівнянні серединного елемента масиву з шуканим значенням, і повторенням алгоритму для тієї або іншої половини (див. двійкове дерево пошуку), залежно від результату порівняння.
Трудомісткість алгоритму , де n — кількість елементів у масиві.
Алгоритм
Рекурсивна версія
Одним із варіантів реалізації алгоритму є рекурсивна функція, що отримує масив, шукане значення та початковий і кінцевий індекси елементів в масиві.
BinarySearch(A[0..N-1], value, low, high) { if (high < low) return -1 // не знайдено mid = (low + high) / 2 if (A[mid] > value) return BinarySearch(A, value, low, mid-1) else if (A[mid] < value) return BinarySearch(A, value, mid+1, high) else return mid // знайдено }
Ітеративна версія
Наведений вище алгоритм можна перетворити на ітеративний:
BinarySearch(A[0..N-1], value) { low = 0 high = N - 1 while (low <= high) { mid = (low + high) / 2 if (A[mid] > value) high = mid - 1 else if (A[mid] < value) low = mid + 1 else return mid // знайдено } return -1 // не знайдено }
Версія без перевірки на рівність
Попередні версії на кожному кроку перевіряють поточний елемент на рівність шуканому. Це може бути досить повільним, якщо порівняння не є швидкими. Також коли в масиві декілька рівних елементів, то попередні алгоритми знаходять будь-який з них. Можна змінити алгоритм, щоб не використовувати порівняння:
BinarySearchFistPosition(A[0, N-1], value) { low = -1 high = N while (high - low > 1) { mid = (high + low) / 2 if (A[mid] >= value) high = mid else low = mid } // Тепер в high знаходиться індекс першого елемента, такого що A[high] >= value. // Якщо це необхідно можна перевірити чи він рівний value if (A[high] > value) // не знайдено, high = 0 чи A[high - 1] < value, A[high] > value else // Знайдено return high } BinarySearchLastPosition(A[0, N-1], value) { low = -1 high = N while (high - low > 1) { mid = (high + low) / 2 if (A[mid] <= value) low = mid else high = mid } // Зараз у high знаходиться індекс першого елемента такого, що A[high] > value, а в A[low] - останнього елемента такого, що A[low] <= value return low }
В сумі ці дві версії можна використовувати, наприклад, щоб знайти скільки елементів масиву рівні даному.
Цікаві дані
Масове використання лінійного пошуку
Двійковий пошук суттєво швидший за лінійний, відносно простий в реалізації і загальновживаний. Проте, в реальних програмах трапляються випадки використання лінійного пошуку, що мають наслідком суттєві проблеми зі швидкодією. Так, в серйозній науковій публікації є такий шматок:
Ми мали програму, яка робила лінійний пошук у дуже великому масиві майже 100 разів на секунду. … Ми відстежили проблему до лінійного пошуку, замінили його на двійковий, і проблема зникла.
який (англ. Jon Bentley) у книзі «Перлини програмування» назвав анекдотом і повідомив, що бачив цю саму історію у багатьох системах. Опублікована на сайті Borland описує проблеми швидкодії, викликані реалізацією певних процедур роботи з базами даних у VCL, які по суті зводяться до використання лінійного пошуку замість двійкового (невикористання індексу таблиці).
Помилки в реалізації
Нескінченний цикл
В тій же книзі Джон Бентлі використовує двійковий пошук як приклад упродовж розділу присвяченого тестуванню та зневадженню. Він наводить типову невірну реалізацію двійкового пошуку, поширену, за його словами, серед професійних програмістів. Невірний код відрізняється від наведеного прикладу рядками
right = mid;
та
else left = mid;
Такий код призводить до нескінченного циклу для багатьох значень шуканого елемента, наприклад, при спробі знайти найбільший елемент масиву.
За спогадами [ 1 квітня 2016 у Wayback Machine.] Джошуа Блоха (англ. Joshua Bloch), йому запала в пам'ять лекція з курсу алгоритмів в Університеті Карнегі Мелон, на якій Джон Бентлі попросив майбутніх кандидатів наук написати двійковий пошук, і розібрав невірний варіант, яких було більшість.
Переповнення
Сам Джошуа є автором реалізації бібліотечної функції двійкового пошуку у Java від Sun. У 2006 році він був шокований ще раз, коли довідався, що ретельно розібрана у Бентлі реалізація, та його власна, яка 9 років знаходилась у бібліотеці Java, містить ще одну помилку. Одна програма, що обробляла великий набір даних, падала через наступний рядок у реалізації:
int mid = (low + high) / 2;
Причиною було те, що low і high були великими, і їх сума викликала програмне переповнення типу int, приводячи до від'ємного значення mid. Таким чином, для обробки великих масивів необхідно писати в реалізації на Java:
int mid = low + ((high - low) / 2);
чи
int mid = (low + high) >>> 1;
Допис Блоха також вразив творця Mono Мігеля де Іказу, але менше вразив розробника Gnome Мортена Веліндера, який також відмітив інші проблеми з арифметикою цього алгоритму.
Після допису Блоха ця помилка була виправлена у Mono, помилка досі присутня у функції bsearch реалізації GNU C Library (glibc) бібліотеки мови Сі .
Див. також
Посилання
- Communications of the ACM "TWA Reservation system"
- (2000) [1986]. Programming Pearls (вид. 2nd edition). Addison-Wesley. с. p34. ISBN .
{{}}
:|pages=
має зайвий текст () - . Архів оригіналу за 14 вересня 2007. Процитовано 3 квітня 2009.
{{}}
: Обслуговування CS1: Сторінки з текстом «archived copy» як значення параметру title () - . Архів оригіналу за 28 листопада 2010. Процитовано 8 жовтня 2010.
- . Архів оригіналу за 17 грудня 2009. Процитовано 8 жовтня 2010.
- Mono-dev: Patch for fixing binary search
- idx = (l + u) / 2;[недоступне посилання з липня 2019]
Джерела
- Ніклаус Вірт (2004) [1975]. Algorithms and Data Structures (PDF). ETH Zürich. с. 366.(англ.)
- Дональд Кнут. Fundamental Algorithms // The Art of Computer Programming. — Massachusetts : Addison–Wesley, 1997. — Т. 1. — 650 с. — .(англ.)
- Дональд Кнут. Seminumerical Algorithms // The Art of Computer Programming. — Massachusetts : Addison–Wesley, 1997. — Т. 2. — 762 с. — .(англ.)
- Томас Кормен; Чарльз Лейзерсон, Рональд Рівест, Кліфорд Стайн (2009) [1990]. Вступ до алгоритмів (вид. 3rd). MIT Press і McGraw-Hill. ISBN .
Це незавершена стаття про алгоритми. Ви можете проєкту, виправивши або дописавши її. |
Вікіпедія, Українська, Україна, книга, книги, бібліотека, стаття, читати, завантажити, безкоштовно, безкоштовно завантажити, mp3, відео, mp4, 3gp, jpg, jpeg, gif, png, малюнок, музика, пісня, фільм, книга, гра, ігри, мобільний, телефон, android, ios, apple, мобільний телефон, samsung, iphone, xiomi, xiaomi, redmi, honor, oppo, nokia, sonya, mi, ПК, web, Інтернет
Dvijkovij poshuk algoritm znahodzhennya zadanogo znachennya u vporyadkovanomu masivi yakij polyagaye u porivnyanni seredinnogo elementa masivu z shukanim znachennyam i povtorennyam algoritmu dlya tiyeyi abo inshoyi polovini div dvijkove derevo poshuku zalezhno vid rezultatu porivnyannya Vizualizaciya dvijkovogo poshuku Trudomistkist algoritmu 1 log 2 n displaystyle 1 log 2 n de n kilkist elementiv u masivi AlgoritmRekursivna versiya Odnim iz variantiv realizaciyi algoritmu ye rekursivna funkciya sho otrimuye masiv shukane znachennya ta pochatkovij i kincevij indeksi elementiv v masivi BinarySearch A 0 N 1 value low high if high lt low return 1 ne znajdeno mid low high 2 if A mid gt value return BinarySearch A value low mid 1 else if A mid lt value return BinarySearch A value mid 1 high else return mid znajdeno Iterativna versiya Navedenij vishe algoritm mozhna peretvoriti na iterativnij BinarySearch A 0 N 1 value low 0 high N 1 while low lt high mid low high 2 if A mid gt value high mid 1 else if A mid lt value low mid 1 else return mid znajdeno return 1 ne znajdeno Versiya bez perevirki na rivnist Poperedni versiyi na kozhnomu kroku pereviryayut potochnij element na rivnist shukanomu Ce mozhe buti dosit povilnim yaksho porivnyannya ne ye shvidkimi Takozh koli v masivi dekilka rivnih elementiv to poperedni algoritmi znahodyat bud yakij z nih Mozhna zminiti algoritm shob ne vikoristovuvati porivnyannya BinarySearchFistPosition A 0 N 1 value low 1 high N while high low gt 1 mid high low 2 if A mid gt value high mid else low mid Teper v high znahoditsya indeks pershogo elementa takogo sho A high gt value Yaksho ce neobhidno mozhna pereviriti chi vin rivnij value if A high gt value ne znajdeno high 0 chi A high 1 lt value A high gt value else Znajdeno return high BinarySearchLastPosition A 0 N 1 value low 1 high N while high low gt 1 mid high low 2 if A mid lt value low mid else high mid Zaraz u high znahoditsya indeks pershogo elementa takogo sho A high gt value a v A low ostannogo elementa takogo sho A low lt value return low V sumi ci dvi versiyi mozhna vikoristovuvati napriklad shob znajti skilki elementiv masivu rivni danomu Cikavi daniMasove vikoristannya linijnogo poshuku Dvijkovij poshuk suttyevo shvidshij za linijnij vidnosno prostij v realizaciyi i zagalnovzhivanij Prote v realnih programah traplyayutsya vipadki vikoristannya linijnogo poshuku sho mayut naslidkom suttyevi problemi zi shvidkodiyeyu Tak v serjoznij naukovij publikaciyi ye takij shmatok Mi mali programu yaka robila linijnij poshuk u duzhe velikomu masivi majzhe 100 raziv na sekundu Mi vidstezhili problemu do linijnogo poshuku zaminili jogo na dvijkovij i problema znikla yakij angl Jon Bentley u knizi Perlini programuvannya nazvav anekdotom i povidomiv sho bachiv cyu samu istoriyu u bagatoh sistemah Opublikovana na sajti Borland opisuye problemi shvidkodiyi viklikani realizaciyeyu pevnih procedur roboti z bazami danih u VCL yaki po suti zvodyatsya do vikoristannya linijnogo poshuku zamist dvijkovogo nevikoristannya indeksu tablici Pomilki v realizaciyi Neskinchennij cikl V tij zhe knizi Dzhon Bentli vikoristovuye dvijkovij poshuk yak priklad uprodovzh rozdilu prisvyachenogo testuvannyu ta znevadzhennyu Vin navodit tipovu nevirnu realizaciyu dvijkovogo poshuku poshirenu za jogo slovami sered profesijnih programistiv Nevirnij kod vidriznyayetsya vid navedenogo prikladu ryadkami right mid ta else left mid Takij kod prizvodit do neskinchennogo ciklu dlya bagatoh znachen shukanogo elementa napriklad pri sprobi znajti najbilshij element masivu Za spogadami 1 kvitnya 2016 u Wayback Machine Dzhoshua Bloha angl Joshua Bloch jomu zapala v pam yat lekciya z kursu algoritmiv v Universiteti Karnegi Melon na yakij Dzhon Bentli poprosiv majbutnih kandidativ nauk napisati dvijkovij poshuk i rozibrav nevirnij variant yakih bulo bilshist Perepovnennya Sam Dzhoshua ye avtorom realizaciyi bibliotechnoyi funkciyi dvijkovogo poshuku u Java vid Sun U 2006 roci vin buv shokovanij she raz koli dovidavsya sho retelno rozibrana u Bentli realizaciya ta jogo vlasna yaka 9 rokiv znahodilas u biblioteci Java mistit she odnu pomilku Odna programa sho obroblyala velikij nabir danih padala cherez nastupnij ryadok u realizaciyi int mid low high 2 Prichinoyu bulo te sho low i high buli velikimi i yih suma viklikala programne perepovnennya tipu int privodyachi do vid yemnogo znachennya mid Takim chinom dlya obrobki velikih masiviv neobhidno pisati v realizaciyi na Java int mid low high low 2 chi int mid low high gt gt gt 1 Dopis Bloha takozh vraziv tvorcya Mono Migelya de Ikazu ale menshe vraziv rozrobnika Gnome Mortena Velindera yakij takozh vidmitiv inshi problemi z arifmetikoyu cogo algoritmu Pislya dopisu Bloha cya pomilka bula vipravlena u Mono pomilka dosi prisutnya u funkciyi bsearch realizaciyi GNU C Library glibc biblioteki movi Si Div takozhSpisok algoritmiv Linijnij poshuk Metod zolotogo peretinuPosilannyaCommunications of the ACM TWA Reservation system 2000 1986 Programming Pearls vid 2nd edition Addison Wesley s p34 ISBN 0201657880 a href wiki D0 A8 D0 B0 D0 B1 D0 BB D0 BE D0 BD Cite book title Shablon Cite book cite book a pages maye zajvij tekst dovidka Arhiv originalu za 14 veresnya 2007 Procitovano 3 kvitnya 2009 a href wiki D0 A8 D0 B0 D0 B1 D0 BB D0 BE D0 BD Cite web title Shablon Cite web cite web a Obslugovuvannya CS1 Storinki z tekstom archived copy yak znachennya parametru title posilannya Arhiv originalu za 28 listopada 2010 Procitovano 8 zhovtnya 2010 Arhiv originalu za 17 grudnya 2009 Procitovano 8 zhovtnya 2010 Mono dev Patch for fixing binary search idx l u 2 nedostupne posilannya z lipnya 2019 DzherelaNiklaus Virt 2004 1975 Algorithms and Data Structures PDF ETH Zurich s 366 angl Donald Knut Fundamental Algorithms The Art of Computer Programming Massachusetts Addison Wesley 1997 T 1 650 s ISBN 0 201 89683 4 angl Donald Knut Seminumerical Algorithms The Art of Computer Programming Massachusetts Addison Wesley 1997 T 2 762 s ISBN 0 201 89684 2 angl Tomas Kormen Charlz Lejzerson Ronald Rivest Kliford Stajn 2009 1990 Vstup do algoritmiv vid 3rd MIT Press i McGraw Hill ISBN 0 262 03384 4 Ce nezavershena stattya pro algoritmi Vi mozhete dopomogti proyektu vipravivshi abo dopisavshi yiyi