Кіріспе

Компьютерлік ғылымда heapsort – салыстыруға негізделген сұрыптау алгоритмі, оны «дұрыс дерек құрылымын пайдалана отырып, таңдау арқылы сұрыптаудың іске асырылуы» деп қарастыруға болады. Таңдау арқылы сұрыптау сияқты, heapsort кіріс деректерін сұрыпталған және сұрыпталмаған аймақтарға бөледі және үлкен элементті сұрыпталмаған аймақтан алып, сұрыпталған аймаққа қою арқылы сұрыпталмаған аймақты қайта-қайта қысқартады. Таңдау арқылы сұрыптаудан айырмашылығы, heapsort сұрыпталмаған аймақтың сызықтық уақытта сканерлеуіне уақытты кетірмейді; керісінше, heapsort әр қадамда ең үлкен элементті тиімді табу үшін сұрыпталмаған аймақты үймелік дерек құрылымында сақтайды. Көптеген машиналарда жақсы іске асырылған жылдам сұрыптаудан сәл баяу болғанымен, оның өте қарапайым іске асырылуы және нашар жағдайдағы уақыттың тиімділігі ([[big O notation runtime]]) артықшылықтары бар. Жылдам сұрыптаудың көптеген нақты нұсқалары, жылдам сұрыптаудың нашарлауын анықтаған жағдайда, қосымша құрал ретінде heapsort-ты пайдаланады. Heapsort – орнында орындалатын алгоритм, бірақ ол тұрақты сұрыптау емес. Heapsort 1964 жылы J. W. J. Williams ұсынған. Бұл мақалада екілік үймелік дерек құрылымы да өз алдына пайдалы құрал ретінде таныстырылды. Сол жылы Роберт В. Флойд бұтақты сұрыптау алгоритмі бойынша бұрынғы зерттеулерін жалғастыра отырып, массивті орнында сұрыптай алатын жетілдірілген нұсқасын жариялады.

Басқа өзгерістер

Тернарлық үйінді сұрыптауы бинарлық үйіндінің орнына тернарлық үйіндіні пайдаланады; яғни, үйіндідегі әрбір элементтің үш баласы бар. Оны бағдарламалау қиынырақ, бірақ алмасу және салыстыру операцияларын тұрақты санда аз жасайды. Себебі, тернарлық үйіндідегі әрбір төмен қарай сырғанау қадамы үш салыстыруды және бір алмастыруды қажет етеді, ал бинарлық үйіндіде екі салыстыру мен бір алмастыру қажет. Тернарлық үйіндідегі екі деңгей 32 = 9 элементті қамтиды, бұл бинарлық үйіндідегі үш деңгейге қарағанда салыстыру санымен бірдей жұмыс істейді, олар тек 23 = 8-ді қамтиды. Бұл негізінен академиялық қызығушылыққа немесе студенттік жаттығу ретінде пайдалы, өйткені қосымша күрделілік шағын үнемдеуге тұрарлық емес, ал төменнен жоғарыға қарай жинақтау екеуін де жеңеді. Жадыда оңтайландырылған үйінді сұрыптауы үйінді сұрыптауының анықтамалық жерін бала санын одан да арттыра отырып жақсартады. Бұл салыстыру санын арттырады, бірақ барлық балалар жадыда бірізді түрде сақталғандықтан, үйінді арқылы өту кезінде қол жетімді кэш желілерінің санын азайтады, бұл өнімділікті жақсартады. Флойдтың үйінді құрылысының стандартты алгоритмі деректер көлемі CPU кэшінен асқан кезде, кэштің көп мөлшерде қатесін тудырады. Үлкен деректер жиынтықтарында жақсы өнімділікті терең бірінші реттік біріктіру арқылы, жоғарыда көрсетілген деңгейге өтуден бұрын барлық субтоптарды бір деңгейде біріктірудің орнына, мүмкіндігінше тезірек субтоптарды біріктіру арқылы алуға болады. Орнына сәйкес келмейтін үйінді сұрыптауы төменнен жоғарыға қарай үйінді сұрыптауды ең нашар жағдайды жою арқылы жақсартады, n log2n + O(n) салыстыруларды кепілдендіреді. Максималды алған кезде бос орынды сұрыпталмаған деректер мәнімен толтырудың орнына оны ешқашан "қайта көтерілмейтін" −∞ күзетші мәнімен толтырады. Бұл элементті орнында (және рекурсивті емес) "QuickHeapsort" алгоритміне примитив ретінде қолдануға болады. Біріншіден, сіз жылдам сұрыптауды орындайсыз, бірақ массивтегі бөлінген деректердің реттілігін кері қайтарасыз. Жалпылығын жоғалтпай, кіші бөлім півоттен үлкен деп есептеңіз, ол массивтің соңында болуы керек, бірақ біздің кері бөліну қадамы оны басында орналастырады. Кіші бөлімнен үйінді құрастырып, оның үстінде орыннан тыс үйінді сұрыптауды орындаңыз, алынған максималарды массивтің соңындағы мәндермен алмастырыңыз. Бұл півоттен кіші, яғни үйірдегі кез келген мәннен кіші, сондықтан -∞ күзетші мәндер ретінде қызмет етеді. Heapsort аяқталғаннан кейін (және півотты массивтің қазір сұрыпталған аяғының алдында жылжытқаннан кейін), бөлімдердің реті кері айналдырылды, ал массивтің басындағы үлкен бөлім дәл сол жолмен сұрыпталуы мүмкін. (Қойрықсыз рекурсия болмағандықтан, бұл жылдам сұрыптаудың O(log n) стекті пайдалануын жояды.) Smoothsort алгоритмі - 1981 жылы Edsger W. Dijkstra әзірлеген үйінді сұрыптауының нұсқасы. Heapsort сияқты smoothsort-тың жоғарғы шегі O(n log n) болып табылады. Смитудсортингтің артықшылығы - егер кіріс белгілі бір дәрежеде сұрыпталған болса, ол O(n) уақытқа жақындайды, ал үйінді сұрыптау бастапқы сұрыпталған күйіне қарамастан O(n log n) орташалайды. Күрделілігіне байланысты тегіс сұрыптау сирек қолданылады. Левкопулос пен Петерсон карталық ағаштардың үйірмесінің негізінде үйірменің түрленуін сипаттайды. Біріншіден, Картезиандық ағаш O(n) уақыт ішіндегі кірістен құрылады және оның тамыры 1 элементті екілік үйіндіге орналастырылады. Содан кейін біз екілік үйіндіден бірнеше рет минимумды шығарып, ағаштың түбір элементін шығарамыз және оның сол және оң балаларын (егер бар болса) қос тізбекті үйіндіге қосамыз, олар өздері Картезиандық ағаштар. Олар көрсеткендей, егер кіріс қазірдің өзінде дерлік сұрыпталған болса, Картезиандық ағаштар өте теңгерімсіз болады, сол және оң балалы бірнеше түйін бар, нәтижесінде бинарлық үйінді кіші болып қалады және алгоритмге O(n log n) -ден жылдам сұрыптауға мүмкіндік береді кіріс қазірдің өзінде дерлік сұрыпталған. Әлсіз үйірмендер секілді бірнеше нұсқалар ең нашар жағдайда n log2 n+O(1) салыстыруды қажет етеді, теориялық минимумға жақын, түйінге бір қосымша күй битін пайдаланады. Бұл қосымша бит алгоритмдерді шынымен орнында емес етеді, егер элементтің ішінде орын табылса, бұл алгоритмдер қарапайым және тиімді, бірақ егер кілтті салыстырулар жеткілікті арзан болса (мысалы, бүтін сандар кілттері), онда тұрақты фактор маңызды емес. Катаяйненнің "соңғы үйінді сұрыптауы" қосымша сақтауды қажет етпейді, n log2 n+O(1) салыстыруды және элементтерді жылжытудың ұқсас санын орындайды. Дегенмен, ол одан да күрделі және салыстырулар өте қымбат болмаса, оны қолданудың қажеті жоқ.

Мысал

Үлгілер { 6, 5, 3, 1, 8, 7, 2, 4 } мәндерін өсу ретімен екі үйінді құру алгоритмдерін пайдаланып сұрыптайды. Салыстырылып жатқан элементтер қалың шрифтпен көрсетілген. Көбінесе жоғары қарай сүзу кезінде екеу, төмен қарай сүзу кезінде үшеу болады, бірақ ағаштың жоғарғы немесе төменгі бөлігіне жеткенде одан аз болуы мүмкін.