Ты чего это такой нервный - написал и сразу все стер? Я вот сейчас озадачен подобной сортировкой, буду делать через массив счетчиков и его "интегрирование". Вот сразу встает вопрос - как будем дробить числа - по битам, по байтам или по словам? Это зависит от длины массива... Вернее результат конечно не зависит, скорость будет разная...
16 гигов счетчиков - не слишком ли круто будет? =))) Лучше всего делать по байтам. Если размер массива много больше чем 65536 можно сделать по словам, будет в два раза быстрее чем по байтам (два прохода вместо 4-х).
Да в собеседовании как-то слышал, кое где дают задание такое. Решил проверить за сколько минут по памяти могу написать. Получилось вроде прикольно. Потом подумал что может кто-нибудь ещё прикольнее сочинит (наверняка). Написал сюда. Интереса сильного к теме не заметил, поэтому стёр.... да и самому уже не особо интересно
Для озабоченых у меня в корзине исходник остался, который вот он =)) Сортирует массив 32 разрядных чисел. В идеале оптимизируется так, что цикл работает без ветвлений (то бишь команд перехода), но в прочем и так сойдёт: Код (Text): ;#define SIZE 100 include 'c:\Fasm\INCLUDE\WIN32AX.INC' .data size=100 array: rw size .code start: call init ; сортировка xor ecx,ecx ; lay xor edx,edx ; mask stc .0: rcr edx,1 mov esi,array mov edi,esi .1: mov eax,[esi] xor eax,ebx test eax,ecx cmovnz edi,esi mov eax,[esi] cmovnz ebx,eax test eax,edx jnz .2 xchg eax,[edi] mov [esi],eax add edi,4 .2: add esi,4 cmp esi,array+size*4 jc .1 stc rcr ecx,1 jnc .0 invoke ExitProcess,0 ; загрузка случайных начальных данных init: mov ebx,1 mov ecx,size mov edi,array .1: mov eax,ebx add eax,edx ror eax,1 mov edx,ebx mov ebx,eax stosd loop .1 ret .end start по скорости, У меня 2-3 секунды на 10 милионов чисел...
Ну думаю от размеров данных в ячейках. и от размеров массива. т.е. от рентабельности постройки массива счётчиков (зачем он нужен, если будет использоваться меньше чем на половину). Следовательно либо по битам, либо применять всё сразу. Старшние разряды какого-нибудь много-метрового массива дробить по словам, средние по байтам, далее по битам. Тут можно даже простую само-аптацию алгоритма делать. По статистике. К тому же не надо целиком менять ячейки в частично сортированном массива, только младшие половинки ячеек.. Короче говоря не алгоритм, а красивая сказка, наворотить можно много....
А вы все еще сортируете числа? Сортировка строк в стандартном алгоритме построения суффиксного массива гораздо интереснее...
Зарелизил через байты... При достаточной длине это конечно много быстрее будет чем по битам или QuickSort... Впечатление портит только доп. массив размером с основной... Что делать будем? Как расставить элементы без доп. масива? Код (Text): Procedure RadixSort(var S:Array of Cardinal; n:Cardinal); var Curr:Cardinal; //байтовое поле CurrB:array [1..4] of byte absolute Curr; Count:array [0..255] of Cardinal; //массив счетчиков D:array of Cardinal; //вспомогательный массив размером с основной i,nb,c1,c2:Cardinal; begin SetLength(D,n); //выделяем память for nb:=1 to 4 do begin //четыре прохода по числу байт for i:=0 to 255 do Count[i]:=0; //очистка счетчиков i:=0; while i<n do begin //заполнение счетчиков Curr:=S[i]; inc(Count[CurrB[nb]]); inc(i); end; c1:=0; c2:=0; for i:=0 to 255 do begin //"интегрирование" счетчиков c2:=c2+c1; c1:=Count[i]; Count[i]:=c2; end; i:=0; while i<n do begin //расстановка массива Curr:=S[i]; D[Count[CurrB[nb]]]:=Curr; inc(Count[CurrB[nb]]); inc(i); end; i:=0; while i<n do begin //копирование частично упорядоченного массива S[i]:=D[i]; inc(i); end; end; SetLength(D,0); //очистка вспомогательного массива end; var X:array of Cardinal; //пример сортировки BEGIN Setlength(X,6); x[0]:=123456789; x[1]:=$FFFFFFFF; x[2]:=0; x[3]:=65536; x[4]:=65535; x[5]:=17; RadixSort(X,6); writeln(x[0]); writeln(x[1]); writeln(x[2]); writeln(x[3]); writeln(x[4]); writeln(x[5]); END.
Дерево наверное хорошо, когда массивы становятся разрежеными (за чем можно следить в процессе работы). А так вся прелесть истино линейного алгоритма теряется.
Код (Text): а почему бы бин. дерево не юзать7777 счётчики не нужны в итоге. Тятя, а что такое глобус... вернее дерево? Точно не знаю, но наверное это структура которая содержит: 1) указатель на данные 2) указатель влево 3) указатель вправо 4) указатель назад... Что-то шипко жирно будет иметь четыре 32-разрядных указателя на одно 32-целое без знака =))) Экономии что-то не видно =))) Не, не любитель я запускать в памяти таких змеев-глистов многоголовых... Вот массивы - это по нашему, и поддерживаются на уровне ассемблера-процессора!!! типа mov eax,[esi+ecx*4] А 256 счетчиков много памяти не отожрут...
Заценил, доп.массива не нашел, рекурсии тоже не нашел... Разве такое возможно для поразрядной сортировки? o: В чем прикол и как развить эти идеи для байт? Имхо байтовая должна в 8 раз быстрее работать для массивов заметно длиннее чем 256 элементов... Код (Text): stc rcr ecx,1 jnc .0 А это что за ковбойство и где такому учат? почему нельзя loop или cmp ecx,32; [esi + ecx*4], что при этом теряем ?
Интересно. Можно в первом проходе по массиву создать 32 таблицы по 1му биту + 32 индексные таблицы, потом каждую отсортировать и потом из индексов восстановить отсортированную таблицу. Но памяти нужно немеряно!
ecx тут маска.. мне надо её заполнять... Притом, я дополнительно имею возможность не тратиться на счётчик....
А нельзя ли для сомневающихся вроде меня рассказать на словах, как это все работает. Возможно, мне нужно по шагам пройти этот код и посмотреть, что и как он сортирует... Как я уже сказал, у меня есть сомнения, что радикс-сорт с массивами возможна без доп массива. Алгоритму нужна так называемая устойчивость, чтобы равные данные ни в коем случае не переставлять местами. Таких алгоритмов не много... Если переставлять местами элементы с нулевым битом и с ненулевым, отгоняя одни в начало массива, а другие в конец, то возможно устойчивость теряется... Насчет маски тоже не все понятно... Получается накопление единиц 1111000 вместо одной 00001000000
Просто сортирует по битам, а не по байтам. А маска защищает числа с одинаковыми старшими битами от перемешивания. Сначала тоже по байтам хотел, но через пару шагов рассужедний бытро дошёл до другово кода. Надеюсь он достаточно понятный:
Да, спасибо, теперь все понятно. n - опережающий индекс m - запаздывающий индекс mask - маска для выделения очередного бита lay - маска для выделения старших разрядов. Мда, круто получается, без доп памяти и рекурсии!!! Кроме шуток, на Шнобеля тянет однозначно! В сети я встречал только рекурсивную битовую сортировку, аналог QuickSort. Есть у этой процедуры маленький косметический деффект - она частенько меняет элемент сам с собой, когда m=n... Некоторые реализации Swap на этом могут обламаться... А всетаки, для 10 млн элементов вариант с 65536 счетчиками обещает в 16 раз быстрее быть... Ну там, без учета попаданий в кеш и все такое... Может побенчимся? =)))