Кіріспе
Іздеу алгоритмі сұрыпталған массив ішіндегі мақсатты мәннің орнын табу, шекті сұрыпталған массивті іздеу. Компьютер ғылымында екілік іздеу, жартылай интервалдық іздеу, логарифмдік іздеу немесе екілік бөлу деп те аталатын бұл алгоритм, сұрыпталған массив ішінде мақсатты мәннің орнын табады. Екілік іздеу мақсатты мәнді массивтің ортаңғы элементімен салыстырады. Егер олар тең болмаса, мақсатты мән бола алмайтын жартысы жойылып, іздеу қалған жартысында ортаңғы элементті тағы да мақсатты мәнмен салыстырып, мақсатты мән табылғанша қайталанады. Егер іздеу қалған жартысы бос күйде аяқталса, мақсатты мән массивте жоқ дегенді білдіреді. Екілік іздеу ең жаман жағдайда логарифмдік уақытта жұмыс істейді, массивтегі элементтер саны болғанда салыстырулар жасайды. Екілік іздеу кіші массивлерден басқа, сызықтық іздеуден жылдам. Дегенмен, екілік іздеуді қолдану үшін массивді алдымен сұрыптау қажет. Бинарлық іздеуге қарағанда тиімді іздеуге болатын хэш-кестелер сияқты, жылдам іздеуге арналған арнайы дерек құрылымдары бар. Алайда, екілік іздеуді кең ауқымды мәселелерді шешу үшін де қолдануға болады, мысалы, массивте мақсатты мән болмаған жағдайда да, мақсатты мәнге қатысты ең кішкентай немесе ең үлкен элементті табу. Екілік іздеудің көптеген нұсқалары бар. Атап айтқанда, фракциялық каскадтау бірнеше массивтегі бірдей мәнді екілік іздеуді жылдамдатады. Фракциялық каскадтау есептеу геометриясы және басқа да көптеген салалардағы көптеген іздеу мәселелерін тиімді шешеді. Экспоненциалды іздеу екілік іздеуді шексіз тізімдерге дейін кеңейтеді. Бинарлық іздеу ағашы мен B-ағашы дерек құрылымдары екілік іздеуге негізделген.
searching a finite sorted array
In computer science, binary search, also known as half interval search, logarithmic search, or binary chop, is a search algorithm that finds the position of a target value within a sorted array. Binary search compares the target value to the middle element of the array. If they are not equal, the half in which the target cannot lie is eliminated and the search continues on the remaining half, again taking the middle element to compare to the target value, and repeating this until the target value is found. If the search ends with the remaining half being empty, the target is not in the array. Binary search runs in logarithmic time in the worst case, making comparisons, where is the number of elements in the array. Binary search is faster than linear search except for small arrays. However, the array must be sorted first to be able to apply binary search. There are specialized data structures designed for fast searching, such as hash tables, that can be searched more efficiently than binary search. However, binary search can be used to solve a wider range of problems, such as finding the next smallest or next largest element in the array relative to the target even if it is absent from the array. There are numerous variations of binary search. In particular, fractional cascading speeds up binary searches for the same value in multiple arrays. Fractional cascading efficiently solves a number of search problems in computational geometry and in numerous other fields. Exponential search extends binary search to unbounded lists. The binary search tree and B tree data structures are based on binary search.
Алгоритм
Бинарлық іздеу сұрыпталған массивтерде жұмыс істейді. Бинарлық іздеу массивтің ортасындағы элементті ізделіп жатқан мәнмен салыстырудан басталады. Егер ізделіп жатқан мән элементке тең болса, оның массивтегі орны қайтарылады. Егер ізделіп жатқан мән элементтен кіші болса, іздеу массивтің төменгі жартысында жалғасады. Егер ізделіп жатқан мән элементтен үлкен болса, іздеу массивтің жоғарғы жартысында жалғасады. Осылайша алгоритм әрбір итерацияда ізделіп жатқан мән бола алмайтын жартысын жояды.
Баламалы рәсім
Жоғарыда көрсетілген процедурада алгоритм әрбір итерацияда ортаңғы элементтің ізделіп отырған мәнмен тең екенін тексереді. Кейбір іске асырулар әрбір итерация кезінде осы тексеруді жіберіп алады. Алгоритм бұл тексеруді тек бір элемент қалғанда ғана (when) жүргізеді. Бұл салыстыру циклын жылдамдатады, себебі әр итерацияда бір салыстырудан бас тартуға болады, бірақ орташа есеппен бір итерацияға көбірек уақыт жұмсалады. Герман Боттенбрух 1962 жылы осы тексеруді жіберіп алатын алғашқы іске асыруды жариялаған.
Орындау уақыты мен кэш пайдалануы
Бинарлық іздеудің жұмысын талдау кезінде тағы бір ескеру қажет мәселе – екі элементті салыстыруға қажетті уақыт. Бүтін сандар мен жолдар үшін қажетті уақыт элементтердің кодтау ұзындығы (әдетте бит саны) артқан сайын сызықтық түрде өседі. Мысалы, 64 биттік таңбасы жоқ бүтін сандар жұбын салыстыру, 32 биттік таңбасы жоқ бүтін сандар жұбын салыстыруға қарағанда екі есе көп битті салыстыруды қажет етеді. Ең нашар жағдай, бүтін сандар тең болғанда туындайды. Бұл, элементтердің кодтау ұзындығы үлкен болған кезде, мысалы, үлкен бүтін сандар немесе ұзын жолдар үшін маңызды болуы мүмкін, себебі бұл элементтерді салыстыруды қымбатқа айналдырады. Сонымен қатар, қозғалатын нүктелік мәндерді (нақты сандардың ең көп таралған цифрлық бейнелеуі) салыстыру, бүтін сандарды немесе қысқа жолдарды салыстыруға қарағанда көбірек уақытты қажет етеді. Көптеген компьютерлік архитектураларда процессордың жедел жады (RAM) -дан бөлек аппараттық кэш-жады болады. Олар процессордың ішінде орналасқандықтан, кэш-жадқа қол жеткізу RAM-ға қарағанда әлдеқайда жылдам, бірақ көбінесе RAM-ға қарағанда әлдеқайда аз дерек сақтайды. Сондықтан, көптеген процессорлар жақында қол жеткізілген жад орындарын және оларға жақын жад орындарын сақтайды. Мысалы, массивтің бір элементіне қол жеткізілген кезде, элементтің өзі және оған жақын орналасқан элементтер RAM-да сақталуы мүмкін, бұл бір-біріне жақын индекстегі массив элементтеріне реттілікпен қол жеткізуді (анықтамалық локалдылық) жылдамдатады. Реттелген массивте, массив үлкен болса, бинарлық іздеу элементтерге реттілікпен қол жеткізетін алгоритмдерден (мысалы, сызықтық іздеу және хэш-кестелердегі сызықтық зондтау) айырмашылығы, қашықтағы жад орындарына секіре алады. Бұл көптеген жүйелерде үлкен массивтер үшін бинарлық іздеудің орындалу уақытын сәл ұзартады.
Бинарлық іздеу және басқа схемалар
Бинарлық іздеумен сұрыпталған массивтер кіргізу және жою операциялары іздеумен кезегімен орындалғанда өте тиімсіз шешім болып табылады, мұндай әр операцияға уақыт қажет. Сонымен қатар, сұрыпталған массивтер жадты пайдалануды күрделендіре алады, әсіресе элементтер массивке жиі қосылғанда. Кіргізу және жою операцияларын әлдеқайда тиімді орындайтын басқа деректер құрылымдары да бар. Бинарлық іздеу нақты сәйкестікті және жиын мүшелігін (көрсетілген мәннің мәндер жиынында бар-жоғын анықтау) жүзеге асыру үшін қолданылуы мүмкін. Нақты сәйкестікті және жиын мүшелігін жылдамдатылған түрде қолдайтын деректер құрылымдары бар. Дегенмен, көптеген басқа іздеу әдістерінен өзгеше, бинарлық іздеу тиімді шамамен сәйкестіру үшін де қолданылуы мүмкін, әдетте мұндай сәйкестіктерді мәндердің түріне немесе құрылымына қарамастан уақыт ішінде орындайды. Сонымен қатар, сұрыпталған массивте тиімді орындалатын ең кішкентай және ең үлкен элементті табу сияқты кейбір операциялар бар.
Сызықтық іздеу
Сызықтық іздеу – нысаналық мәнді тапқанша әрбір жазбаны тексеріп шығатын қарапайым іздеу алгоритмі. Сызықтық іздеуді тізімде жасауға болады, бұл массивке қарағанда енгізу мен жою операцияларын жылдамдатуға мүмкіндік береді. Реттелген массивлер үшін бинарлық іздеу, массив қысқа болмаса, сызықтық іздеуден жылдам. Алайда, массивді алдымен реттеу қажет. Жылдам сұрыптау және біріктіру сұрыптау сияқты, элементтерді салыстыруға негізделген барлық сұрыптау алгоритмдері ең жаман жағдайда кем дегенде салыстыруды қажет етеді. Сызықтық іздеуден өзгеше, бинарлық іздеуді тиімді шамамен сәйкестіру үшін қолдануға болады. Реттелген массивте тиімді орындалатын, ал реттелмеген массивте орындалмайтын, ең кішкентай және ең үлкен элементті табу сияқты операциялар бар.
Ағаштар
Бинарлық іздеу ағашы – бинарлық іздеу принципіне негізделген жұмыс істейтін бинарлық ағаш дерек құрылымы. Ағаш жазбалары реттелген тәртіппен орналасады, және ағаштағы әрбір жазбаны бинарлық іздеуге ұқсас алгоритмді қолданып, орташа есеппен логарифмдік уақытта іздеуге болады. Бинарлық іздеу ағаштарында енгізу және жою операциялары да орташа есеппен логарифмдік уақытты қажет етеді. Бұл реттелген массивтерге сызықтық уақытта енгізу және жою операцияларынан жылдам болуы мүмкін, сонымен қатар бинарлық ағаштар реттелген массивте мүмкін болатын барлық операцияларды – ауқымдық және шамамен сұрауларды орындау мүмкіндігін сақтайды. Дегенмен, хэштеу келесі кішкентай, келесі үлкен және ең жақын кілтті табу сияқты шамамен сәйкес келу үшін тиімді емес, себебі сәтсіз іздеуде мақсатты жазбаның жоқтығы туралы ғана ақпарат беріледі. Бинарлық іздеу мұндай сәйкестіктер үшін өте қолайлы және оларды логарифмдік уақытта орындайды. Бинарлық іздеу шамамен сәйкес келуді де қолдайды. Ең кіші және ең үлкен элементті табу сияқты кейбір операцияларды сұрыпталған массивтерде тиімді орындауға болады, бірақ хэш-кестелерде – емес. Шамамен нәтижелер алу үшін Блум сүзгілері, хэштеуге негізделген басқа да ықтималдық дерек құрылымы, кілттерді біттік массив және бірнеше хэш функцияларын қолданып кодтау арқылы кілттер жиынтығын сақтайды. Блум сүзгілері көбінесе біттік массивтерге қарағанда жадты тиімдірек пайдаланады және көп ұзамайды: хэш функцияларымен мүшелік сұраныстарына тек уақыт қажет. Алайда, Блум сүзгілері жалған оң нәтижелерге бейім. Блум сүзгісінің күрделілігін жақсартатын немесе жою мүмкіндігін қосатын жақсартулар бар; мысалы, құпия сүзгісі осы артықшылықтарды алу үшін құпия хэштеуін пайдаланады.
Басқа деректер құрылымдары
Кейбір жағдайларда екілік іздеуді жақсартуға мүмкіндік беретін дерек құрылымдары бар, сондай-ақ сұрыпталған массивтер үшін қолжетімді басқа операцияларды да орындауға болады. Мысалы, іздеулер, шамамен сәйкестіктер және сұрыпталған массивтерге қолжетімді операциялар ван Эмде Боас ағаштары, біріктіру ағаштары, трилер және биттік массивлер сияқты арнайы дерек құрылымдарында екілік іздеуге қарағанда тиімдірек болуы мүмкін. Бұл арнайы дерек құрылымдары көбінесе тек белгілі бір қасиеттері бар кілттерді (әдетте кішкентай бүтін сандар кілттер) пайдалану арқылы ғана жылдамдыққа ие болады, сондықтан мұндай қасиеттері жоқ кілттер үшін көп уақыт немесе жад қажет болуы мүмкін. Іс жүзінде, интерполяциялық іздеу кішкентай массивтер үшін екілік іздеуден баяу болады, себебі интерполяциялық іздеуге қосымша есептеулер қажет. Оның уақыт күрделілігі екілік іздеуге қарағанда баяу өседі, бірақ бұл тек үлкен массивтер үшін қосымша есептеулерді толық өтеуге мүмкіндік береді.
Фракциялық каскадтау
Фракциялық каскадтау – бірнеше рет сұрыпталған массивтердегі бірдей элементті екілік іздеуді жылдамдату әдісі. Әрбір массивті жеке іздеуге уақыт қажет, мұндағы – массивтер саны. Фракциялық каскадтау әрбір массивте әр элемент туралы және оның басқа массивтердегі орны туралы нақты ақпарат сақтау арқылы осы уақытты дейін азайтады. Фракциялық каскадтау бастапқыда әртүрлі есептеу геометриясы мәселелерін тиімді шешу үшін әзірленген. Фракциялық каскадтау деректерді өндіру және Интернет протоколы маршрутизациясы сияқты басқа да салаларда қолданылған.
Бинарлық шулы іздеу
Шулы екілік іздеу алгоритмдері алгоритмнің массив элементтерін сенімді түрде салыстыра алмайтын жағдайды шешеді. Әр элемент жұбы үшін алгоритмнің дұрыс емес салыстыру жасауының белгілі бір ықтималдығы бар. Шулы екілік іздеу нысананың дұрыс орнын белгілі бір ықтималдықпен таба алады, бұл нәтижедегі позицияның сенімділігін анықтайды. Кез келген шулы екілік іздеу процедурасы орташа алғанда кем дегенде салыстыру жасауы керек, мұнда – екілік энтропия функциясы, ал – процедураның дұрыс емес позицияны беру ықтималдығы. Шулы екілік іздеу мәселесін Рени-Улам ойынының бір түрі деп қарастыруға болады, ол жиырма сұрақ ойынының нұсқасы, онда жауаптар қате болуы мүмкін.
Кванттық бинарлық іздеу
Классикалық компьютерлер бинарлық іздеуді орындағанда дәл ішкі циклдің ең нашар жағдайымен шектеледі. Бинарлық іздеуге арналған кванттық алгоритмдер әлі де сұраныстардың үлесімен (классикалық процедураның ішкі циклдарын көрсетеді) шектеледі, бірақ тұрақты коэффициент бірден кем, бұл кванттық компьютерлерде уақыттың күрделілігін азайтады. Кез келген нақты кванттық бинарлық іздеу процедурасы – яғни, әрқашан дұрыс нәтиже беретін процедура – ең нашар жағдайда кем дегенде сұраныс қажет етеді, мұнда табиғи логарифм болып табылады. Ең нашар жағдайда сұраныстар саны бойынша жұмыс істейтін нақты кванттық бинарлық іздеу процедурасы бар. Қарама-қарсылығында, Гровер алгоритмі ретсіз элементтер тізімін іздеу үшін ең оңтайлы кванттық алгоритм болып табылады және ол сұраныс қажет етеді.
Тарих
Тізімдерді жылдам іздеу үшін оларды сұрыптау идеясы ежелгі заманға дейін барады. Ең ерте белгілі мысалы – б.з.д. 200 жылға дейінгі Вавилоннан шыққан Инакибит Ану тақташасы. Тақташада шамамен 500 сексагезимал сан және олардың кері шамалары лексикографиялық тәртіппен орналастырылған, бұл нақты жазбаны іздеуді жеңілдеткен. Сонымен қатар, Эгей аралдарында әлфавит бойынша бірінші әрпімен сұрыпталған бірнеше есімдер тізімі табылды. 1286 жылы аяқталған «Католикон» латын сөздігі сөздерді әліпбилік тәртіппен реттеу ережесін, жай ғана алғашқы бірнеше әріптер бойынша емес, алғаш рет сипаттады. 1946 жылы Джон Мокли екілік іздеуді Мур мектебінің лекциялары аясында алғаш рет атады, бұл есептеу техникасының негізгі және іргелі колледж курсы болды. 1957 жылы Уильям Уэсли Петерсон интерполяциялық іздеудің алғашқы әдісін жариялады. 1960 жылға дейін жарияланған әрбір екілік іздеу алгоритмі ұзындығы екінің дәрежесінен бірге кем массивтер үшін ғана жұмыс істеді, содан кейін Деррик Генри Лемер барлық массивтерде жұмыс істейтін екілік іздеу алгоритмін жариялады. 1962 жылы Герман Боттенбрух ALGOL 60-та екілік іздеуді іске асыруды ұсынды, ол теңдік салыстыруын соңына орналастырды, орташа итерациялар санын бірге арттырды, бірақ итерация басына салыстырулар санын бірге азайтты.
Орындау мәселелері
Джон Бентли кәсіби бағдарламашылар курсында екілік іздеуді тапсырма ретінде бергенде, оның тоқсан пайызы бірнеше сағат жұмыс істегеннен кейін дұрыс шешім таба алмады, себебі дұрыс емес іске асырулар жұмыс істемеді немесе сирек жағдайларда қате жауап берді. 1988 жылы жарияланған зерттеуде оның дұрыс коды жиырма оқулықтың тек бесеуінде ғана кездесетіні көрсетілді. Сонымен қатар, Бентлидің 1986 жылы жарияланған «Программирование инжуиры» кітабындағы екілік іздеуді іске асыруында жиырма жылдан астам уақытқа дейін байқалмай қалған ағып кету қатесі болды. Java бағдарламалау тілі кітапханасының екілік іздеу іске асыруы тоғыз жылдан астам уақыт бойы бірдей ағып кету қатесіне тап болды. Іс жүзіндегі іске асыруда индекстерді көрсету үшін қолданылатын айнымалылар көбінесе белгілі бір мөлшерде (бүтін сандар) болады, бұл өте үлкен массивтер үшін арифметикалық ағып кетуге әкелуі мүмкін. Егер аралықтың ортасы есептелсе, онда орта нүктені сақтау үшін қолданылатын дерек типінің бүтін сандарының диапазонынан асып кетуі мүмкін, тіпті егер және диапазонда болса да. Егер және теріс емес болса, орта нүктені есептеу арқылы бұған жол берілмейді. Циклдің тоқтату шарттары дұрыс анықталмаса, шексіз цикл пайда болуы мүмкін. Егер ол саннан асып кетсе, іздеу сәтсіз аяқталады және сәтсіздік туралы хабарлама берілуі керек. Сонымен қатар, мақсатты элемент табылғанда циклден шығу керек немесе бұл тексеру соңына жылжытылған жағдайда, іздеудің сәтті немесе сәтсіз аяқталғанын тексеру керек. Бентли екілік іздеуді дұрыс іске аспаған бағдарламашылардың көпшілігі тоқтату шарттарын анықтауда қателік жасағанын анықтады. C++ стандартты кітапханасы екілік іздеу, ең төменгі шек, ең жоғарғы шек және тең ауқым функцияларын ұсынады. D стандартты кітапханасы Phobos, std.range модулінде sort және assumeSorted функциялары арқылы қайтарылатын SortedRange типін ұсынады, оның құрамында contains, equalRange, lowerBound және trisect әдістері бар, олар кездейсоқ кіруді ұсынатын диапазон үшін әдепкі бойынша екілік іздеу әдістерін қолданады. COBOL реттелген кестелерде екілік іздеуді орындау үшін SEARCH ALL операторын ұсынады. Go-ның sort стандартты кітапханасы пакетіне Search, SearchInts, SearchFloat64s және SearchStrings функциялары кіреді, олар жалпы екілік іздеуді жүзеге асырады, сондай-ақ бүтін сандардың, қалқымалы нүктелі сандардың және жолдардың тізімдерін іздеу үшін арнайы іске асыруларды ұсынады. Java стандартты java.util пакетіндегі және кластарында екілік іздеудің жүктемелі статикалық әдістерінің жиынтығын ұсынады, олар Java массивтерінде және Тізімдерде екілік іздеуді орындау үшін қолданылады. Microsoft .NET Framework 2.0 жиынтық базалық сыныптарында екілік іздеу алгоритмінің статикалық жалпы нұсқаларын ұсынады. Мысалы, System.Array әдісі BinarySearch<T>(T[] array, T value). Objective-C үшін Cocoa фреймворкі Mac OS X 10.6+ жүйесінде NSArray indexOfObject:inSortedRange:options:usingComparator: әдісін ұсынады. Apple-дің Core Foundation C фреймворкі CFArrayBSearchValues функциясын да қамтиды. Python әр енгізілгеннен кейін тізімді сұрыптаудың қажеті жоқ, тізімді сұрыпталған тәртіппен сақтайтын bisect модулін ұсынады. Ruby-дің Array класы bsearch әдісін қамтиды.
An infinite loop may occur if the exit conditions for the loop are not defined correctly. Once exceeds , the search has failed and must convey the failure of the search. In addition, the loop must be exited when the target element is found, or in the case of an implementation where this check is moved to the end, checks for whether the search was successful or failed at the end must be in place. Bentley found that most of the programmers who incorrectly implemented binary search made an error in defining the exit conditions. C++'s standard library provides the functions binary search , lower bound , upper bound and equal range D's standard library Phobos, in std. range module provides a type SortedRange (returned by sort and assumeSorted functions) with methods contains , equaleRange , lowerBound and trisect , that use binary search techniques by default for ranges that offer random access. COBOL provides the SEARCH ALL verb for performing binary searches on COBOL ordered tables. Go's sort standard library package contains the functions Search, SearchInts, SearchFloat64s, and SearchStrings, which implement general binary search, as well as specific implementations for searching slices of integers, floating point numbers, and strings, respectively. Java offers a set of overloaded binarySearch static methods in the classes and in the standard java. util package for performing binary searches on Java arrays and on Lists, respectively. Microsoft's NET Framework 2.0 offers static generic versions of the binary search algorithm in its collection base classes. An example would be System. Array's method BinarySearch<T>(T[] array, T value). For Objective C, the Cocoa framework provides the NSArray indexOfObject:inSortedRange:options:usingComparator: method in Mac OS X 10.6+. Apple's Core Foundation C framework also contains a CFArrayBSearchValues function. Python provides the bisect module that keeps a list in sorted order without having to sort the list after each insertion. Ruby's Array class includes a bsearch method with built in approximate matching.