Кіріспе

Салыстыруға негізделген сұрыптау алгоритмі

Компьютерлік ғылымда, smoothsort – салыстыруға негізделген сұрыптау алгоритмі. Heapsort-тың бір түрі, ол 1981 жылы Эдсгер Дийкстрамен ойлап табылып жарияланды. Heapsort сияқты, smoothsort – орнында орындалатын алгоритм және үлкен O белгісімен операциялардың жоғарғы шегі бар, бірақ ол тұрақты сұрыптау емес. Smoothsort-тың артықшылығы – егер кіріс деректер қандай да бір деңгейде сұрыпталған болса, ол O(n) уақытына жақындайды, ал heapsort бастапқы сұрыпталған күйіне қарамастан O(n log n) орташа уақытты қажет етеді.

Төменге қарай сырып алу

Негізгі сырғанау операциясы (Дайкстра "триккл" деп атайды) үйінді инвариантын тек тамыр түйінінде бұзылу мүмкін болған жағдайда қалпына келтіреді. Егер тамыр түйіні өзінің кез келген баласынан кіші болса, ол ең үлкен баласымен ауыстырылады және процесс жаңа кіші ағашта тамыр түйінімен қайталанады. Smoothsort пен бинарлық максималдық үйінді арасындағы айырмашылық – әрбір созылудың тамыры үшінші "қадамбалы" бойынша реттелуі керек: алдыңғы созылудың тамыры. Сондықтан төмен қарай сырғанау процедурасы төрттік салыстырулар сериясынан басталады (тамыр түйіні және үш баласы), қадамбалы максималды элемент болмайынша, содан кейін үштік салыстырулар сериясынан басталады (тамыр және екі баласы), тамыр түйіні өзінің соңғы орнын тауып, инварианттар қайта орнатылғанша. Әрбір ағаш толық екілік ағаш: әрбір түйінде екі баласы болады немесе баласы жоқ. Стандартты жасырын бинарлық үйіндіде кездесетін бір баланың ерекше жағдайымен айналысудың қажеті жоқ. (Бірақ қадамбалы байланыстардың ерекше жағдайы осы үнемдеуді толықтырады.) O(log n) созылулар бар, олардың әрқайсысы O(log n) тереңдігіндегі ағаш болып табылады, сондықтан әрбір сырғанау операциясын орындау уақыты O(log n) арқылы шектеледі.

Оң жаққа элементті қосу арқылы үйме аймағын кеңейту

Қосымша элемент созылулар тізбегіне (бір-біріне қосылмаған үйме құрылымдарының тізімі) қосылғанда, ол жаңа бір элементтік созылу құрайды немесе екі оң жақ созылуды біріктіріп, олардың екі түбіріне ата-ана болып, тізбекте оларды алмастыратын жаңа созылу құрайды. Қай жағдай орын алатыны тек қазіргі созылулардың мөлшеріне (және соңында қосылған элементтің индексіне) байланысты. Дийкстра созылулардың мөлшері L(k+1) және L(k) болған жағдайда ғана біріктіріледі деп көрсетті, яғни, екі тізбектелген Леонардо саны болғанда; жаңа созылудың мөлшері L(k+2) болады. Екі жағдайда да, жаңа элемент үйме құрылымындағы дұрыс орнына ие болу үшін төменге сұрыпталуы керек. Жаңа түйін бір элементтік созылу болса да, ол алдыңғы созылудың түбірімен салыстырылып сұрыпталуы тиіс.

Оңтайландыру

Дикстраның алгоритмі толық үйінді инварианты өсу кезеңінің соңында ғана қажет екенін байқау арқылы жұмысты үнемдейді, бірақ ол әрбір аралық қадамда қажет емес. Атап айтқанда, элементтің баласынан үлкен болуы талабы тек соңғы ағаш түбірлері үшін ғана маңызды. Сондықтан, элемент қосылғанда, оның болашақ ата-анасының орнын анықтаңыз. Егер ол сұрыпталуға тиіс қалған мәндер диапазонында болса, баласы жоқ деп есептеп, тек ағымдағы ағаш ішінде ғана сұрыптауды жүргізіңіз.

Басты элементті оң жақтан алып тастау арқылы үйінді аймағын кішірейту

Бұл кезеңде созылулар тізбегінің пішіні өсу кезеңінің өзгерістерін кері бағытта қайталайды. Жапырақ түйінін бөліп шығару кезінде ешқандай жұмыс қажет емес, бірақ жапырақ емес түйін үшін оның екі баласы жаңа созылулардың түбірлеріне айналады және созылулардың түбірлері тізбегіндегі дұрыс орнына жылжытылуы керек. Бұл екі рет төмен қарай икемдеу арқылы жүзеге асырылады: бірінші сол бала үшін, содан кейін оң бала үшін (оның балама баласы сол бала болған). Толық екілік ағаштағы түйіндердің жартысы жапырақтар болғандықтан, бұл орташа есеппен әр түйін үшін бір рет төмен қарай икемдеу операциясын орындауға мүмкіндік береді.

Оңтайландыру

Жаңа ашылған тамырлардың қалыпты балаларына қатысты дұрыс реттелгендігі белгілі, дау тек олардың өгей балаларына қатысты реттілігі туралы. Сондықтан, үйіндіні қысқарту кезінде, төмен қарай іріктеудің алғашқы қадамын өгей баламен бір салыстыру арқылы жеңілдетуге болады. Егер алмасу болса, келесі қадамдарда толық төрт тармақты салыстыру қажет.

Талдау

Smoothsort алдын ала сұрыпталған массивті өңдеуге O(n) уақыт алады, ең нашар жағдайда O(n log n) уақыт алады және көптеген дерлік сұрыпталған кірістерде линейлік өнімділікке жетеді. Дегенмен, ол барлық дерлік сұрыпталған тізбектерді оңтайлы түрде өңдемейді. Ретсіздіктің өлшемі ретінде инверсиялар санын пайдалану (i < j және A[i] > A[j] болатын индекс жұптарының саны; кездейсоқ сұрыпталған кіріс үшін бұл шамамен n²/4), O(n log n) инверсиясы бар кіріс тізбектері болуы мүмкін, бұл оған Ω(n log n) уақыт алуға себеп болады, ал басқа бейімделмелі сұрыптау алгоритмдері осы жағдайларды O(n log log n) уақытында шеше алады. Smoothsort алгоритмі Леонардо үйірмесіндегі барлық ағаштардың өлшемдерін жадында сақтауға қабілетті болуы керек. Олар рет бойынша сұрыпталғандықтан және барлық реттер ерекше болғандықтан, бұл әдетте қандай реттердің бар екенін көрсететін бит векторы арқылы жасалады. Сонымен қатар, ең үлкен рет ең көп дегенде O(log n) болғандықтан, бұл биттерді O(1) машиналық сөздермен кодтауға болады, трансдихотомиялық машиналық модельді қабылдап. O(1) машиналық сөздері бір машиналық сөзбен бірдей емес екенін ескеріңіз. 32 биттік вектор 1=L(32) = 7049155-тен кіші өлшемдер үшін ғана жеткілікті. 64 биттік вектор 1=L(64) = 34335360355129 ≈ 2⁴⁵-тен кіші өлшемдер үшін қолданылады. Жалпы, бұл 1/log₂([[Алтын қатынас векторының биттері өлшемнің бір бітіне.

Ағаштың сорты

Smoothsort-тен шабыдаланған қарапайым алгоритм – тополь сорты. Голландиялық полидерде жиі кездесетін, көлемі азая беретін ағаштар қатарынан аталған бұл алгоритм, көбінесе сұрыпталмаған деректер үшін smoothsort-тан аз салыстырулар жасайды, бірақ толық сұрыпталған деректер үшін сызықтық уақытқа жете алмайды. Тополь сортының ерекшелігі – әртүрлі ағаштардың тамырлары сұрыпталмайды; оларды бір үйіндіге байланыстыратын "балалық" сілтемелер жоқ. Оның орнына, екінші кезеңде үйінді қысқартылған сайын, ең үлкен элементті табу үшін тамырлар ізделіп қаралады. n қысқару қадамы болғандықтан, олардың әрқайсысы ең үлкенін табу үшін O(log n) тамырды іздеуі керек, сондықтан тополь сортының ең жақсы жағдайдағы орындалу уақыты O(n log n) құрайды. Авторлар Леонардо ағаштарының орнына толық екілік ағаштарды пайдалануды ұсынады, бірақ бұл одан да қарапайым ету үшін жасалған, алайда бұл аз маңызды өзгеріс. Бұл құрылымды жалпы мақсаттағы басымдық кезегі ретінде "кейіннен жүргізілетін үйінді" деп атау ұсынылған, бұл имплицитті биномдық үйіндіге қарағанда қарапайым құрылымда O(1) амортизацияланған енгізу уақытына қол жеткізеді.

Қолданбалар

musl C кітапханасы qsort функциясын іске асыру үшін smoothsort алгоритмін пайдаланады.