Комментарии 155
Что за алгоритм? Кем разработан?
Знакома ли авторам big-O нотация? Если вы говорите об асимптотической сложности алгоритма, выражение 2*N не имеет смысла, пишут O(N). Иначе вам придется пояснять что такое N. Операции? Сравнения?
По поводу алгоритма и сложности. Давно известно что алгоритмы основанные только на сравнениях имеют оптимальную сложность O(nlogn). Любые варианты с меньшей сложностью так или иначе используют ограниченность пространства ключей, либо другие свойства данных. Скорее всего вы изобрели radix, или counting sort, или trie, или какой-то вариант другой известной идеи. Может быть вы придумали что-то новое и полезное, в таком случае снимаю шляпу! Но из статьи этого не видно.
Сам факт того что какой-то кастомный алгоритм сортировки для определенного типа данных может быть быстрее std::sort никого не удивит. std::sort это универсальный алгоритм основанный только на сравнениях, который не использует знания о типах данных никаким образом. Когда программист вызывает std::sort, он как бы говорит системе: интерпретируй мои данные как абстрактные ключи и используй operator< для их сравнения, я знаю что я делаю. Создатели stl не пытались предоставить наибыстрейший алгоритм сортировки для всех возможных типов данных.
Прекрасно знаю, что означает O(N).
С каждым элементом выполняются определенные действия. Это одно N.
Нет, вы явно не знаете, что означает O(N).
в нем нет сравнений элементов друг с другом
Значит, это не универсальный алгоритм сортировки. Что и требовалось доказать.
Сложность std:sort — O(N·log(N)).
log(4 500 000) = 6,6.
Т.е сравниваются алгоритмы сложности (как бы) «О(6N)» и «O(2N)», а это по сути одна и та же сложность. Так же при такой схожей сложности еще влияет и качество реализации алгоритма.
Чтобы их сравнить нужно чтобы log(N) был как минимум на порядок больше двух.
Это речь о 10^20 строк. Как часто нам приходится сортировать такое количество данных? Не думаю что в реальном использовании этих алгоритмов можно почувствовать значительную разницу.
количество слов? букв? бит? разрядность регистра в процессоре?
Ссылку бы на алгоритм… А так какой-то конь сферический. И еще бы описание методики измерения — как мерялось время? Как память? И уж вообще шикарно бы код выложить.
Описание методики измерения времени — стандартное (код ниже)
start = clock();
программа сортировки (сначала одна, потом другая);
finish = clock();
duration = (double)(finish — start);
std::cout << "\n Время сортировки — ", std::cout << duration, std::cout << "\n";
А сколько раз проверяли? А память как считали? А что с одинаковыми значениями? А сложность у вас наихудшая, средняя, ещё какая?
В 7-ом тесте «Война и мир» представлена 4-ре раза, а весь текст дублирован дважды.
Очень много — это сколько? 100, 1000, 100000, миллион,…? Вообще такие вещи делают в цикле сотни тысяч раз.
А что будет на уже отсортированном массиве? На отсортированном в обратную сторону? На случайном?
Память — обычно делают свой heap и считают, плюс максимальный размер стека...
Судя по описанию, вы изобрели Поразрядную сортировку или Radix sort. (https://ru.m.wikipedia.org/wiki/%D0%9F%D0%BE%D1%80%D0%B0%D0%B7%D1%80%D1%8F%D0%B4%D0%BD%D0%B0%D1%8F_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0) И да, она хорошо работает в задаче о сортировке слов.
Вики говорит, что TimSoft заточен под случаи, когда у нас нередки упорядоченные или частично упорядоченные подмассивы и что это сочетание сортировок слиянием и вставкой. В описании алгоритма приводится всё по шагам. Выглядит, как оптимизированный под конкретные случаи merge sort.
Ничего о сортировке по первой букве, затем по второй не увидел https://ru.m.wikipedia.org/wiki/Timsort
Да и доступная визуализация алгоритма это показывает.
Признаться, я не понимаю, что вы говорите.
TimSort описан иначе. По вашей схеме у вас будет M подмассивов, где M зависит от N, и каждый подмассивов будет сортироваться столько раз, сколько букв в самом длинном слове. Если сложность одной сортировки по одной букве N, длина наибольшего слова K, то мы получим, O(N^2*K).
Товарищи по цеху, если я ошибаюсь, то поправите мою оценку описанного алгоритма.
Можно не писать штуки вроде O от конкретного числа?
Я вам написал, что такая оценка получается при использовании алгоритма сортировки O(N).
Если взять O(nlog(n)), то в итоге получится O(N^2log(N)*K)
Это стандартная схема сортировки текстовых данных на современном этапе хоть в python, хоть в java.
Какой конкретно способ сортировки вы называете "стандартной схемой сортировки текстовых данных в python"? Приведите конкретную функцию.
У "прогонов" сложности не бывает. У них только время выполнения бывает. Сложность бывает у алгоритмов. И у алгоритмов она бывает разной (амортизированная, средняя, для худшего случая и т.п.)
Т.е. ваше утверждение, что ваш алгоритм бытрее std:sort на ЛЮБЫХ данных — некорректен. СУЩЕСТВУЕТ контрпример, на которм стандартный алгоритм будет быстрее.
Увы, без деталей реализации невозможно такой контрпример найти.
Существует МАССА алгоритмов, которые быстрее стандратного на определенном типе данных. Ваш — один из них.
Поймите, интерес к деталям обусловлен не желанием украсть вашу коммерческую тайну, а просто мы пытаемся подтолкнуть вас к осознанию положения вещей.
— ни одного сравнения, но нужно очень много памяти.
— ни одного сравнения, но нужно очень много памяти.А ещё, сортировать так можно только чисел, диапазон значений которых не превышает размер доступного адресного пространства. И с количеством повторов, не превышающим диапазон значений адресуемой ячейки. И только если это прямо всамделишные массивы, во всякие списки, хэшы и прочие высоко-уровневые структуры скорость вставки и удаления тоже зависит от количества элементов.
Берем массив [0, MAXINT_64], и сортируем вашим алгоритмом.
Вам понадобится MAXINT_64 сравнений, чтобы пройти по «отсортированной» памяти и найти все (2) вставленных значения, а классическому алгоритму будет достаточно 1-го сравнения.
Что значит худшего случая?
Без деталей алгоритма не скажешь. Где-то — полностью отсортированный массив. Где-то — отсортированный задом наперед. Где-то — полностью случайные данные. Где-то — массив, состоящий из одного значения элементов…
На таких данных ваш алгоритм вполне может показывать линейную зависимость.
Только именно это и надо указывать в заголовке.
Вы, случайно, с любителем анимированных флагов и определителем случайностей не знакомы?
Хмммммм… *подозрительно щурится*
- Я построил самый быстрый самолёт!
- А какую скорость замеряли: взлета, посадки, загрузки, максимальную полетную, воздушную (калиброванную, истинную, эквивалентную), путевую, сваливания, крейсерскую или другую какую может?
- А что такое скорость?
Допустим у нас есть некий алгоритм, реализован в виде функции, на вход которой приходит массив. Внутри этой функции есть 3 невложенных foreach:
someFunction(someArray) {
foreach(someArray){
}
foreach(someArray){
}
foreach(someArray){
}
return someResult
}
Какова сложность данного алгоритма в big-O нотации?
Внутри циклов нет других циклов.
А у такого варианта какова сложность:
someFunction(someArray) {
foreach(someArray){
foreach(someArray){
foreach(someArray){
}
}
}
return someResult
}
А если не сложно, объясните пожалуйста кто-нибудь, почему из серии тестов выбирается наименьшее значение? Почему не среднее?
habr.com/ru/post/489958
на «хороших» данных работает лучше всех, на случайных данных — уже не так уж и экстремально быстро.
На данный момент как раз почему-то в качестве набора данных для сортировки использован естественный текст. Причина?
В итоге он реализовал немного допиленный arm qemu, который логирует в файл выполняемые инструкции в процессе работы программы. Почему ARM? бОльшая линейность и зависимость только от оптимизации компилятора, а не особенности предсказания ветвлений.
Подход позволяет посчитать с точностью до процессорной инструкции время вычисления, плюс заодно напрямую получить точное количество обработанных байт оперативной памяти.
Для профессоров заниматься таким абсолютно нормально, чистая наука, все дела. Но на практике нам всем гораздо интереснее скорость работы с учётом всего того, что он хочет не учитывать.
Зато подсчет инструкций позволяет в один проход получить повторяемый результат, а не гонять набор тестов, прогревая процессорный кэш, дисковый кэш и потом занимаясь статистикой — минимальное время взять? среднее? медиану?
Здесь бенчмарк достаточно запустить один раз и все случайные факторы просто не оказывают влияние. Да, не нравится ограниченность именно RISC архитектурой, но…
Уважаемый автор, вы предлагаете читателям судить ниочём. Нет ни алгориитма, ни описания его работы, ни упоминания на каком оборудовании проводились ваши опыты. Также видно, что для оценки сложности вы не использовали стандартных инструментов оценки сложности (нотация О большое для классов функций). Ознакомьте нас хотя бы с оценкой сложности алгоритма std:sort в вашей системе.
Недавно был разработан алгоритм быстрой сортировки, сложность которого определяется как 2*N (2 умножить на N).
Простой вопрос: это алгоритм общего назначения или специализированный?
Если я правильно предполагаю, то автор пишет про "Сортировку Таноса" (автор называл её "Русской сортировку половинками", но я категорически против использования такого названия), которая является велосипедом вариантом QuickSort. Видимо по некомпетентности valemak не распознал велосипед и написал вышеупомянутую статью (ничего страшного, бывает).
Однако, дальше хуже:
- valemak пригласил на Хабр пользователя Danilin78 (автор упомянутой сортировки), который умудрился отличится двумя вариантами своей статьи (1, 2) получившими недвусмысленную оценку "бред" и т.п.
- Теперь valemak пригласил пользователя HabrArkady, который написал обсуждаемую статью о "вновь разработанном алгоритме сортировки", демонстрируя элементарное незнание темы, без описания алгоритма и/или демонстрации исходного кода, неся откровенную пургу в комментариях и т.д и т.п.
Поэтому у меня вопрос к valemak: кто все эти люди и что вы там все употребляете?
Я люблю изучать сортировки (считайте, что это моё хобби) и время от времени публикую статьи об этих алгоритмах. Свои методы я не изобретаю, рассказываю о классических.
Мне иногда пишут авторы собственных наработок, просят дать инвайт. Как правило, даю :-) За саморегулирующийся Хабр не переживаю. Также осмелюсь заметить, что в комментариях обсуждения статей моих «крестников» всегда получаются бурными и доставляющими :-)
Ну так и что в итоге с "сортировкой воронкой"?
Если дадите ссылку на исходный код референстной или оптимизированной реализации, то обещаю выложить результаты тестов с исходниками.
Это модифицированная сортировка слиянием. Используется linked list.
Есть текущий подмассив, изначально пустой. Идем по исходному массиву, который сортируем.
Первый элемент просто добавляем в подмассив, следующие сравниваем с головой и хвостом подмассива, если меньше головы добавляем в голову, если больше хвоста добавляем в хвост. Для добавления в голову и нужен linked list, иначе придется сдвигать все элементы. Хотя наверно можно заменить его на массив в 2 раза больше исходного.
Если элемент находится между головой и хвостом, откладываем подмассив в буфер подмассивов, создаем новый пустой подмассив, добавляем туда.
После прохода по исходному массиву есть некоторое количество отсортированных подмассивов. Мержим их попарно, всегда берем самые минимальные по длине. Можно либо отсортировать по длине другим алгоритмом (автор предлагал пузырек), либо поддерживать отсортированность при добавлении. Но после каждого слияния длина результирующего массива меняется, надо это учитывать.
Изначально у автора было несколько рабочих подмассивов, они получаются каждый следующий короче предыдущего, поэтому он назвал алгоритм "сортировка воронкой". Для произвольных данных число сравнений в этом случае увеличивается, поэтому он сделал один подмассив, а название оставил.
В TimSort тоже есть определение отсортированных подмассивов (run), там они определяются в самом массиве, сравнение происходит с предыдущим элементом. В реализации MergeSort это тоже иногда добавляют, сам алгоритм от этого не меняется. Соответственно, от такого модифицированного MergeSort сортировка воронкой отличается только дополнительным сравнением с головой текущего run. Она значительно лучше работает на данных, специально для нее подходящих (2, 8, 2, 8, 1, 9, ...), на всех остальных работает чуть хуже, так как часто происходят 2 сравнения и потом все равно создание нового подмассива из одного элемента вместо одного сравнения на элемент для первоначального разбиения в модифицированном MergeSort. Может быть некоторый выигрыш от того, что мержатся минимальные подмассивы, а не соседние, но в TimSort это обрабатывается лучше.
В обычном MergeSort для первоначального разбиения будет ноль сравнений, так как просто всегда берется подмассив из 1 элемента, но в большинстве случаев это увеличивает число сравнений при слиянии. Для полностью случайных данных обычный MergeSort будет чуть лучше модифицированного (на N/2 сравнений), что заметно на небольших массивах. Для всех остальных случаев будет лучше модифицированный MergeSort или TimSort. Сортировка воронкой подходит для очень узкого круга вариантов.
И, наконец, если очень хочется ругаться, то пришли e-mail. Поругаемся. А хамить здесь, не надо!!!
Самый главный результат — это то, что по новому алгоритму, выигрыш по быстродействию более 15%, а по затратам на память — практически двукратный.
… по сравнению с чем?
(это просто к разговору "надо знать, о чем рассуждаешь")
Да, этой сортировкой можно, сортировать все.
Покажите результаты сравнения (и код бенчмарка) для сравнения объектов с интерфейсом a.GoesBefore(b)
. Или опишите, каким образом ваш алгоритм работает для таких объектов.
Потому что в этих тестах используются строки (для которых известен алгоритм сортировки со сложностью O(n)), а не элементы, для которых определена только операция сравнения (и для которых доказана невозможность сортировки со сложностью быстрее O(n log n)). Без демонстрации на операциях сравнения ваше утверждение о том, что ваша сортировка универсальна, бездоказательно.
Если ваш алгоритм требует определения для элементов больше отношения "a < b", то мерятся скоростью следует не c std::sort
(универсальной сортировкой), а чем-то менее универсальным. В этом случае рекомендую этот пост — там Travis Downs ничего нового не придумал, но итеративно с танцами и песнями пояснениями и иллюстрациями дошел до хороших показателей для radixsort. Соответственно, хотелось-бы увидеть сопоставление результатов с вашим алгоритмом.
Кроме этого, при сравнении с std::sort
следует измерять результаты для разных случаев (с разным распределением и упорядочиванием) исходных данных. В качестве заготовки могу предложить более-менее приемлемый тест и показать результаты (на всякий — сам тест критиковать не стоит, а просто сделать лучше/правильно и опубликовать).
На всякий дополню — добавлять оцениваемые сортировки лучше в stresstest и запускать его-же.
HabrArkady, вы покажите результаты stresstest
с вашим алгоритмом или не намерены этого делать?
Вы ничего не должны, но я предлагаю проверить вашу сортировку простейшим набором тестов. Вам нужно:
- Клонировать git-репозиторий https://github.com/erthink/sort;
- Для проверки собрать проект посредством
CMake
и запуститьrunme
; - Добавить вашу реализацию сортировки по аналогии добавления radixsort;
- Запустить
runme
и показать результаты.
Для информации:
- это простейший бенчмарк сортировок сделанный сотрудником google ~10 лет назад.
- я добавил несколько сценариев распределения данных (для оценки скорости yysort-сортировки сделанной для libmdbx.
- только-что добавил сборку посредством CMake и упомянутую ранее реализацию radixsort.
Running tests with random:
extra.h yysort1_int64 - ok, 822818.0 usec
extra.h yysort2_int64 - ok, 854933.0 usec
extra.h sort_rela589n_int64 - ok, 1576849.0 usec
extra.h radix_sort7_int64 - ok, 185674.0 usec
sort.h tim_sort - ok, 1402058.0 usec
sort.h quick_sort - ok, 1077905.0 usec
extra.h std_sort_int64 - ok, 1009962.0 usec
extra.h std_stable_int64 - ok, 1059595.0 usec
sort.h heap_sort - ok, 1102937.0 usec
sort.h merge_sort - ok, 1421193.0 usec
sort.h shell_sort - ok, 1862364.0 usec
sort.h merge_sort_in_place - ok, 1246581.0 usec
sort.h grail_sort - ok, 1699774.0 usec
sort.h sqrt_sort - ok, 1455058.0 usec
stdlib qsort - ok, 1927199.0 usec
-------
Running tests with random 50% duplicates:
extra.h yysort1_int64 - ok, 810166.0 usec
extra.h yysort2_int64 - ok, 849615.0 usec
extra.h sort_rela589n_int64 - ok, 1572379.0 usec
extra.h radix_sort7_int64 - ok, 212029.0 usec
sort.h tim_sort - ok, 1398433.0 usec
sort.h quick_sort - ok, 1088323.0 usec
extra.h std_sort_int64 - ok, 1065503.0 usec
extra.h std_stable_int64 - ok, 1071353.0 usec
sort.h heap_sort - ok, 1093484.0 usec
sort.h merge_sort - ok, 1415888.0 usec
sort.h shell_sort - ok, 1838834.0 usec
sort.h merge_sort_in_place - ok, 1253441.0 usec
sort.h grail_sort - ok, 1693643.0 usec
sort.h sqrt_sort - ok, 1453816.0 usec
stdlib qsort - ok, 1949698.0 usec
-------
Running tests with random two values:
extra.h yysort1_int64 - ok, 248878.0 usec
extra.h yysort2_int64 - ok, 122961.0 usec
extra.h sort_rela589n_int64 - ok, 89906420.0 usec
extra.h radix_sort7_int64 - ok, 145132.0 usec
sort.h tim_sort - ok, 436794.0 usec
sort.h quick_sort - ok, 112741.0 usec
extra.h std_sort_int64 - ok, 272012.0 usec
extra.h std_stable_int64 - ok, 309151.0 usec
sort.h heap_sort - ok, 558226.0 usec
sort.h merge_sort - ok, 492002.0 usec
sort.h shell_sort - ok, 350249.0 usec
sort.h merge_sort_in_place - ok, 364930.0 usec
sort.h grail_sort - ok, 586547.0 usec
sort.h sqrt_sort - ok, 552624.0 usec
stdlib qsort - ok, 772211.0 usec
-------
Running tests with random of 0..9:
extra.h yysort1_int64 - ok, 391730.0 usec
extra.h yysort2_int64 - ok, 301675.0 usec
extra.h sort_rela589n_int64 - ok, 7404398.0 usec
extra.h radix_sort7_int64 - ok, 133223.0 usec
sort.h tim_sort - ok, 835698.0 usec
sort.h quick_sort - ok, 272618.0 usec
extra.h std_sort_int64 - ok, 417282.0 usec
extra.h std_stable_int64 - ok, 547843.0 usec
sort.h heap_sort - ok, 944833.0 usec
sort.h merge_sort - ok, 796068.0 usec
sort.h shell_sort - ok, 674562.0 usec
sort.h merge_sort_in_place - ok, 678547.0 usec
sort.h grail_sort - ok, 1639136.0 usec
sort.h sqrt_sort - ok, 868220.0 usec
stdlib qsort - ok, 1242882.0 usec
-------
Running tests with mixed-pattern (1/2 sorted, 1/6 reverse, 1/3 random):
extra.h yysort1_int64 - ok, 613579.0 usec
extra.h yysort2_int64 - ok, 663289.0 usec
extra.h sort_rela589n_int64 - ok, 657258.0 usec
extra.h radix_sort7_int64 - ok, 183325.0 usec
sort.h tim_sort - ok, 552537.0 usec
sort.h quick_sort - ok, 838606.0 usec
extra.h std_sort_int64 - ok, 792180.0 usec
extra.h std_stable_int64 - ok, 525126.0 usec
sort.h heap_sort - ok, 1032734.0 usec
sort.h merge_sort - ok, 748048.0 usec
sort.h shell_sort - ok, 1676758.0 usec
sort.h merge_sort_in_place - ok, 586180.0 usec
sort.h grail_sort - ok, 953395.0 usec
sort.h sqrt_sort - ok, 772525.0 usec
stdlib qsort - ok, 1062228.0 usec
-------
Running tests with mixed-pattern 50% duplicates:
extra.h yysort1_int64 - ok, 609025.0 usec
extra.h yysort2_int64 - ok, 660484.0 usec
extra.h sort_rela589n_int64 - ok, 659025.0 usec
extra.h radix_sort7_int64 - ok, 225606.0 usec
sort.h tim_sort - ok, 622718.0 usec
sort.h quick_sort - ok, 824485.0 usec
extra.h std_sort_int64 - ok, 788281.0 usec
extra.h std_stable_int64 - ok, 522923.0 usec
sort.h heap_sort - ok, 1031538.0 usec
sort.h merge_sort - ok, 754849.0 usec
sort.h shell_sort - ok, 1642628.0 usec
sort.h merge_sort_in_place - ok, 590366.0 usec
sort.h grail_sort - ok, 990525.0 usec
sort.h sqrt_sort - ok, 774448.0 usec
stdlib qsort - ok, 1124386.0 usec
-------
Running tests with mixed-pattern two values:
extra.h yysort1_int64 - ok, 200132.0 usec
extra.h yysort2_int64 - ok, 83036.0 usec
extra.h sort_rela589n_int64 - ok, 67483405.0 usec
extra.h radix_sort7_int64 - ok, 140106.0 usec
sort.h tim_sort - ok, 160123.0 usec
sort.h quick_sort - ok, 97190.0 usec
extra.h std_sort_int64 - ok, 225158.0 usec
extra.h std_stable_int64 - ok, 205413.0 usec
sort.h heap_sort - ok, 511215.0 usec
sort.h merge_sort - ok, 356849.0 usec
sort.h shell_sort - ok, 297061.0 usec
sort.h merge_sort_in_place - ok, 162143.0 usec
sort.h grail_sort - ok, 374851.0 usec
sort.h sqrt_sort - ok, 409156.0 usec
stdlib qsort - ok, 566768.0 usec
-------
Running tests with mixed-pattern of 0..9:
extra.h yysort1_int64 - ok, 285522.0 usec
extra.h yysort2_int64 - ok, 203379.0 usec
extra.h sort_rela589n_int64 - ok, 3868783.0 usec
extra.h radix_sort7_int64 - ok, 134041.0 usec
sort.h tim_sort - ok, 306421.0 usec
sort.h quick_sort - ok, 184143.0 usec
extra.h std_sort_int64 - ok, 312547.0 usec
extra.h std_stable_int64 - ok, 295135.0 usec
sort.h heap_sort - ok, 887521.0 usec
sort.h merge_sort - ok, 465153.0 usec
sort.h shell_sort - ok, 500991.0 usec
sort.h merge_sort_in_place - ok, 304824.0 usec
sort.h grail_sort - ok, 873295.0 usec
sort.h sqrt_sort - ok, 540994.0 usec
stdlib qsort - ok, 746061.0 usec
-------
Running tests with sorted:
extra.h yysort1_int64 - ok, 106663.0 usec
extra.h yysort2_int64 - ok, 16666.0 usec
extra.h sort_rela589n_int64 - ok, 69891.0 usec
extra.h radix_sort7_int64 - ok, 251164.0 usec
sort.h tim_sort - ok, 11735.0 usec
sort.h quick_sort - ok, 251402.0 usec
extra.h std_sort_int64 - ok, 173910.0 usec
extra.h std_stable_int64 - ok, 143127.0 usec
sort.h heap_sort - ok, 964730.0 usec
sort.h merge_sort - ok, 282217.0 usec
sort.h shell_sort - ok, 224989.0 usec
sort.h merge_sort_in_place - ok, 24654.0 usec
sort.h grail_sort - ok, 436444.0 usec
sort.h sqrt_sort - ok, 283779.0 usec
stdlib qsort - ok, 456411.0 usec
-------
Running tests with sorted 93.75%:
extra.h yysort1_int64 - ok, 278289.0 usec
extra.h yysort2_int64 - ok, 289340.0 usec
extra.h sort_rela589n_int64 - ok, 655408.0 usec
extra.h radix_sort7_int64 - ok, 260584.0 usec
sort.h tim_sort - ok, 468728.0 usec
sort.h quick_sort - ok, 637118.0 usec
extra.h std_sort_int64 - ok, 329171.0 usec
extra.h std_stable_int64 - ok, 336014.0 usec
sort.h heap_sort - ok, 984870.0 usec
sort.h merge_sort - ok, 519161.0 usec
sort.h shell_sort - ok, 1534410.0 usec
sort.h merge_sort_in_place - ok, 518192.0 usec
sort.h grail_sort - ok, 800571.0 usec
sort.h sqrt_sort - ok, 661784.0 usec
stdlib qsort - ok, 888571.0 usec
-------
Running tests with reverse:
extra.h yysort1_int64 - ok, 181535.0 usec
extra.h yysort2_int64 - ok, 194451.0 usec
extra.h sort_rela589n_int64 - ok, 84785.0 usec
extra.h radix_sort7_int64 - ok, 256737.0 usec
sort.h tim_sort - ok, 31284.0 usec
sort.h quick_sort - ok, 301640.0 usec
extra.h std_sort_int64 - ok, 177571.0 usec
extra.h std_stable_int64 - ok, 197487.0 usec
sort.h heap_sort - ok, 909687.0 usec
sort.h merge_sort - ok, 382207.0 usec
sort.h shell_sort - ok, 344173.0 usec
sort.h merge_sort_in_place - ok, 281081.0 usec
sort.h grail_sort - ok, 491918.0 usec
sort.h sqrt_sort - ok, 333204.0 usec
stdlib qsort - ok, 511167.0 usec
-------
Running tests with 111......000:
extra.h yysort1_int64 - ok, 157486.0 usec
extra.h yysort2_int64 - ok, 20157.0 usec
extra.h sort_rela589n_int64 - ok, 89831003.0 usec
extra.h radix_sort7_int64 - ok, 138863.0 usec
sort.h tim_sort - ok, 16507.0 usec
sort.h quick_sort - ok, 43632.0 usec
extra.h std_sort_int64 - ok, 183356.0 usec
extra.h std_stable_int64 - ok, 151969.0 usec
sort.h heap_sort - ok, 476663.0 usec
sort.h merge_sort - ok, 288034.0 usec
sort.h shell_sort - ok, 236196.0 usec
sort.h merge_sort_in_place - ok, 58724.0 usec
sort.h grail_sort - ok, 248106.0 usec
sort.h sqrt_sort - ok, 353212.0 usec
stdlib qsort - ok, 458765.0 usec
-------
Running tests with 999..., 888..., ..., ...000:
extra.h yysort1_int64 - ok, 149749.0 usec
extra.h yysort2_int64 - ok, 19980.0 usec
extra.h sort_rela589n_int64 - ok, 32356259.0 usec
extra.h radix_sort7_int64 - ok, 135767.0 usec
sort.h tim_sort - ok, 32825.0 usec
sort.h quick_sort - ok, 99056.0 usec
extra.h std_sort_int64 - ok, 175027.0 usec
extra.h std_stable_int64 - ok, 155548.0 usec
sort.h heap_sort - ok, 820527.0 usec
sort.h merge_sort - ok, 298793.0 usec
sort.h shell_sort - ok, 254553.0 usec
sort.h merge_sort_in_place - ok, 107271.0 usec
sort.h grail_sort - ok, 429893.0 usec
sort.h sqrt_sort - ok, 414603.0 usec
stdlib qsort - ok, 493637.0 usec
-------
Running tests with all same:
extra.h yysort1_int64 - ok, 166858.0 usec
extra.h yysort2_int64 - ok, 21707.0 usec
extra.h sort_rela589n_int64 - ok, 69098.0 usec
extra.h radix_sort7_int64 - ok, 113107.0 usec
sort.h tim_sort - ok, 12040.0 usec
sort.h quick_sort - ok, 18011.0 usec
extra.h std_sort_int64 - ok, 186969.0 usec
extra.h std_stable_int64 - ok, 141784.0 usec
sort.h heap_sort - ok, 66827.0 usec
sort.h merge_sort - ok, 287558.0 usec
sort.h shell_sort - ok, 225105.0 usec
sort.h merge_sort_in_place - ok, 24957.0 usec
sort.h grail_sort - ok, 199244.0 usec
sort.h sqrt_sort - ok, 295538.0 usec
stdlib qsort - ok, 437948.0 usec
-------
Running tests with sorted blocks of length 10:
extra.h yysort1_int64 - ok, 780905.0 usec
extra.h yysort2_int64 - ok, 817650.0 usec
extra.h sort_rela589n_int64 - ok, 1581537.0 usec
extra.h radix_sort7_int64 - ok, 182992.0 usec
sort.h tim_sort - ok, 1293210.0 usec
sort.h quick_sort - ok, 1029897.0 usec
extra.h std_sort_int64 - ok, 973319.0 usec
extra.h std_stable_int64 - ok, 924195.0 usec
sort.h heap_sort - ok, 1078477.0 usec
sort.h merge_sort - ok, 1267130.0 usec
sort.h shell_sort - ok, 1723112.0 usec
sort.h merge_sort_in_place - ok, 1112339.0 usec
sort.h grail_sort - ok, 1576277.0 usec
sort.h sqrt_sort - ok, 1324452.0 usec
stdlib qsort - ok, 1722064.0 usec
-------
Running tests with sorted blocks of length 100:
extra.h yysort1_int64 - ok, 653574.0 usec
extra.h yysort2_int64 - ok, 689053.0 usec
extra.h sort_rela589n_int64 - ok, 1564217.0 usec
extra.h radix_sort7_int64 - ok, 182998.0 usec
sort.h tim_sort - ok, 675106.0 usec
sort.h quick_sort - ok, 906428.0 usec
extra.h std_sort_int64 - ok, 832817.0 usec
extra.h std_stable_int64 - ok, 682833.0 usec
sort.h heap_sort - ok, 1047375.0 usec
sort.h merge_sort - ok, 933192.0 usec
sort.h shell_sort - ok, 1457265.0 usec
sort.h merge_sort_in_place - ok, 889346.0 usec
sort.h grail_sort - ok, 1296572.0 usec
sort.h sqrt_sort - ok, 1058781.0 usec
stdlib qsort - ok, 1352663.0 usec
-------
Running tests with sorted blocks of length 10000:
extra.h yysort1_int64 - ok, 324255.0 usec
extra.h yysort2_int64 - ok, 376492.0 usec
extra.h sort_rela589n_int64 - ok, 284086.0 usec
extra.h radix_sort7_int64 - ok, 184740.0 usec
sort.h tim_sort - ok, 124746.0 usec
sort.h quick_sort - ok, 625609.0 usec
extra.h std_sort_int64 - ok, 491734.0 usec
extra.h std_stable_int64 - ok, 250881.0 usec
sort.h heap_sort - ok, 986073.0 usec
sort.h merge_sort - ok, 393951.0 usec
sort.h shell_sort - ok, 551140.0 usec
sort.h merge_sort_in_place - ok, 322268.0 usec
sort.h grail_sort - ok, 652629.0 usec
sort.h sqrt_sort - ok, 465226.0 usec
stdlib qsort - ok, 638257.0 usec
-------
Running tests with swapped size/2 pairs:
extra.h yysort1_int64 - ok, 713246.0 usec
extra.h yysort2_int64 - ok, 747018.0 usec
extra.h sort_rela589n_int64 - ok, 1508257.0 usec
extra.h radix_sort7_int64 - ok, 265747.0 usec
sort.h tim_sort - ok, 1176319.0 usec
sort.h quick_sort - ok, 993433.0 usec
extra.h std_sort_int64 - ok, 852194.0 usec
extra.h std_stable_int64 - ok, 865713.0 usec
sort.h heap_sort - ok, 1074433.0 usec
sort.h merge_sort - ok, 1163080.0 usec
sort.h shell_sort - ok, 1831217.0 usec
sort.h merge_sort_in_place - ok, 1072136.0 usec
sort.h grail_sort - ok, 1438544.0 usec
sort.h sqrt_sort - ok, 1222052.0 usec
stdlib qsort - ok, 1635037.0 usec
-------
Running tests with swapped size/8 pairs:
extra.h yysort1_int64 - ok, 388071.0 usec
extra.h yysort2_int64 - ok, 415601.0 usec
extra.h sort_rela589n_int64 - ok, 920980.0 usec
extra.h radix_sort7_int64 - ok, 257616.0 usec
sort.h tim_sort - ok, 657143.0 usec
sort.h quick_sort - ok, 713389.0 usec
extra.h std_sort_int64 - ok, 451258.0 usec
extra.h std_stable_int64 - ok, 455000.0 usec
sort.h heap_sort - ok, 1009091.0 usec
sort.h merge_sort - ok, 667092.0 usec
sort.h shell_sort - ok, 1659759.0 usec
sort.h merge_sort_in_place - ok, 675202.0 usec
sort.h grail_sort - ok, 947886.0 usec
sort.h sqrt_sort - ok, 798388.0 usec
stdlib qsort - ok, 1060413.0 usec
-------
Running tests with known evil data (odd/even swap):
extra.h yysort1_int64 - ok, 106596.0 usec
extra.h yysort2_int64 - ok, 119683.0 usec
extra.h sort_rela589n_int64 - ok, 72005.0 usec
extra.h radix_sort7_int64 - ok, 247649.0 usec
sort.h tim_sort - ok, 93710.0 usec
sort.h quick_sort - ok, 280980.0 usec
extra.h std_sort_int64 - ok, 167934.0 usec
extra.h std_stable_int64 - ok, 163389.0 usec
sort.h heap_sort - ok, 954945.0 usec
sort.h merge_sort - ok, 312337.0 usec
sort.h shell_sort - ok, 232719.0 usec
sort.h merge_sort_in_place - ok, 21145.0 usec
sort.h grail_sort - ok, 438797.0 usec
sort.h sqrt_sort - ok, 285045.0 usec
stdlib qsort - ok, 507681.0 usec
-------
Running tests with known evil data (odd/even hi/low swap):
extra.h yysort1_int64 - ok, 113151.0 usec
extra.h yysort2_int64 - ok, 71402.0 usec
extra.h sort_rela589n_int64 - ok, 140752.0 usec
extra.h radix_sort7_int64 - ok, 244312.0 usec
sort.h tim_sort - ok, 292957.0 usec
sort.h quick_sort - ok, 494097.0 usec
extra.h std_sort_int64 - ok, 162164.0 usec
extra.h std_stable_int64 - ok, 196847.0 usec
sort.h heap_sort - ok, 943394.0 usec
sort.h merge_sort - ok, 387820.0 usec
sort.h shell_sort - ok, 439202.0 usec
sort.h merge_sort_in_place - ok, 365635.0 usec
sort.h grail_sort - ok, 655214.0 usec
sort.h sqrt_sort - ok, 426086.0 usec
stdlib qsort - ok, 669278.0 usec
В том числе, видно как ведет себя "новый метод сортировки массива" от rela589n.
Никаким.
Тогда каким образом вы с ее помощью сортируете объекты для которых определена только операция сравнения?
Да, этой сортировкой можно, сортировать все. Там нет привязки, к чему-либо.
К чему вопрос?
К тому, что ваше утверждение, что ваша сортировка универсальна — некорректно.
Можно сортировать текстовую информацию, целые и десятичные числа, положительные и отрицательные.
Но это не "все". Это текстовая информация, и некоторые виды чисел. У std::sort
такого ограничения нет, и поэтому ваше сравнение некорректно.
Более того, я подозреваю, что вы не можете просто сортировать числа, вам надо их представить в некой специализированной форме.
Можно сортировать текстовую информацию
О, кстати. Текстовую информацию, да. Любую?
Простой тест — вот есть три слова: linea, llamar, lonja. В каком порядке они будут после вашей сортировки?
И что подразумевается под «Любую?»?
К тому, что ваше утверждение, что ваша сортировка универсальна — некорректно. Почему? Я написал, что я могу сортировать текстовую информацию, целые и десятичные числа, положительные и отрицательные. Программа сортирует. После сортировки полностью, один в один, совпадает сортировкой, получаемой функцией std::sort.
Если Вы работаете в кодировке ANSI и сортируете по возрастанию, то так и останется. Кода в кодировке ANSI: i-105, l-108, o-111. Первая буква «l» — у всех общая, поэтому сортироваться будет по 2-ой букве.
А это неправильно. Согласно правилам испанского языка (по-моему, в середине 90-х это отменили, правда, но не суть), должно быть вот так:
linea
lonja
llamar
А все потому, что ll
— это диграф, на самом деле. И его нельзя сортировать просто по кодам в кодировке.
А если надо неотмененное правило, то пожалуйста: n ñ o
, в Юникоде — 006E 00F1 006F
.
И что подразумевается под «Любую?»?
А вот ровно пример выше: вы не смогли корректно отсортировать эту текстовую информацию.
Почему?
Потому что есть объекты, которые ваша сортировка сортировать не умеет.
Я написал, что я могу сортировать текстовую информацию, целые и десятичные числа, положительные и отрицательные.
Это называется "специализированная сортировка". Универсальная сортировка, по определению, та, которая умеет сортировать все, для чего определена операция сравнения.
И в немецком: ss → ß → st
И, подозреваю, в любом другом языке, в котором используются грависы, акуты, циркумфлексы и прочие седильи и лигатуры.
Как можно сортировать без сравнений?ну вот же, например: radix sort, pigeonhole sort, counting sort. Эти сортировки имеют сложность худшего случая O(N), но у них у всех есть существенные ограничения, как и у Вашей. Вы же сами сказали, что Ваша сортировка «не относится к классу сортировок посредством сравнений». Зачем тогда спрашиваете?
Сознательного подгона и мухлежа. Подгон и мухлеж очень часто возникает в результате незнания, потому в университетах долго и сложно учат методикам проведения и анализа экспериментов, и годами два раза в неделю тренируют студентов практикумами, что бы они набрались опыта в этом деле. Правильные тесты — это сложно.
для того, чтобы о чем-то рассуждать, надо знать, о чем рассуждаешь
Вот-вот. Жаль, что вы сами не следуете этому принципу, путая IDE с языком программирования и не зная, как работает O-нотация (сложность 2*N)
Вы попали в точку, судя по ответам ниже.
А как Вы отнесетесь, если я сообщу следующую информацию.
Я разработал алгоритм деления длинных чисел и написал программу на C++ в Visual Studio 2017. Также были проверены эти данные на MathLab, Java и других программах и языках.
Получил следующие результаты:
Разделил 100-значное десятичное число на 35-значное десятичное число в цикле 100 000 раз.
Время расчета на тестах (MathLab, Java и другие программы и языки) составляет — от 1/2 минуты и выше.
На моей программе рассчитывается на одном процессоре — 0,1 секунды.
Затем я разделил 225-значное десятичное число на 53-значное десятичное число в цикле 1 000 000 раз. На моей программе рассчитывается на одном процессоре – около 3 секунд.
- Вы так и не показали воспроизводимых результатов оценки вашей сортировки. Инструкции вам были предложены неделю назад.
- Закодируйте и покажите ваш "бенчмарк деления" на актуальной версии python (там внутри GMP) и
посмешитепорадуйте нас результатами.
Пока вы этого не сделаете на ваши придумки не рационально обращать внимание.
А как Вы отнесетесь, если я сообщу следующую информацию.
Так же, как к тому, что вы написали в статье: как к ничем не подтвержденному заявлению.
А у меня есть алгоритм деления больших чисел, написанный на C лет 10 назад, я его запустил и получил следующие результаты.
Разделил 200-значное десятичное число на 73-значное десятичное число в цикле 100 000 раз.
На моей программе рассчитывается на одном процессоре — 0,07 секунды.
Затем я разделил 339-значное десятичное число на 117-значное десятичное число в цикле 1 000 000 раз.
На моей программе рассчитывается на одном процессоре – около 1 секунды.
Присоединюсь к ораторам выше: что за алгоритм? что значит 2N? где код на гитхабе? Или это очередная секретная разработка ФСО совместно с ротой охраны штаба ЗВО?
О быстрой сортировке, сложности 2*N