Как называется этот алгоритм сортировки ?

Перед вступлением - пост очень длинный, если не втянет - листать придётся долго

Вступление

Стояли у меня некоторые рабочие задачи, и я не задавался вопросом сортировки

Но в рабочем процессе я увидел, что изобретённый мною велосипед - ещё и сортировать умеет

При ближайшем рассмотрении я увидел, что велосипед ещё и едет быстрее, чем Quick Sort

Забегая наперёд, асимптотика алгоритма сортировки по времени - O(log(n^k)), и такого я не смог найти в интернетах

Вот здесь https://habr.com/ru/post/689738/ самый большой список, который я нашёл, описание и тесты 27 алгоритмов сортировки

Статья довольно свежая, на данный момент ей всего месяц

Там я кстати тоже отметился в комментариях, но мне пока ничего не ответили

Вот ещё некоторая информация https://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8

Учитывая всё это, плюс что конструкция и идея алгоритма, простая как топор - я развернул довольно обширное тестирование на эту тему

И как следствие - вы имеете возможность наблюдать этот пост-статью

Основная часть

Среда тестирования - VDS KVM 4-Core 2.4GHz, 6 GB RAM, Ubuntu 16.04.6 LTS, Apache/2.4.18, PHP 7.0

Участники тестирования

- сортировка выборкой, написанная на коленке

- быстрая сортировка (рекурсивная), взятая отсюда https://russianblogs.com/article/6814675765/

- встроенная в PHP функция сортировки, asort

- моя сортировка, так как я пока что не знаю как она называется - имею моральное право, дать ей проектное название - рельсовая сортировка

Ещё есть варианты - индексная сортировка, матричная сортировка, линейная сортировка, разреженная сортировка

Типовая реализация - ссылка https://pastebin.com/ZCEZ5fR6

На гитхабах я не сижу, потому что у меня банально нет на это времени, поэтому пусть будет pastebin

И да, любителям гайдлайнов и "красивого кода" - передаю свой пламенный привет

Предварительно

Победитель по скорости работы - asort, но она только что и делает - сортирует, а значит оптимизирована только на выполнение этой задачи, к тому же встроенная - что для меня не удивительно

В моей работе часто нужно делать что-то ещё помимо сортировки, что показательно - в данном конкретном случае, сортировка мне в принципе была не нужна

Примечание: для реализации моего алгоритма - нужны отрицательные индексы массива, так как значения превращаются в ключи

Знаю что реализовать можно на JavaScript и C# без дополнительных осложнений

А вот для Pascal/Delphi и C/C++ - нужно дополнительно сдвигать все значения на +min если оно отрицательное, и хранить объекты, которым можно назначить состояние отсутствия элементов; да и для таких языков - мой алгоритм под вопросом, так как вычислительная сложность скорее всего будет другой

За другие языки программирования - сказать не могу

Методика тестирования

В цикле генерируется массив случайных чисел в диапазоне [-1000;1000], длинной от 1 до N, где N - исследуемая величина

На каждой итерации - копия массива сортируется каждым алгоритмом, 1 000 раз

N в разных случаях был либо 10 000, либо 3 500

Лимит на единичное выполнение теста алгоритмом - 3 секунды, за это время алгоритм должен отсортировать массив, 1 000 раз

Ниже график, построенный по собранным данным, в Excel

Как называется этот алгоритм сортировки ? IT, Программирование, Алгоритм, Сортировка, Исследования, Тестирование, График, Длиннопост

По оси X - количество элементов массива

По оси Y - время выполнения в секундах

Мой алгоритм продолжал тестироваться и после трёх секунд

Потому что дело в отсеивании пиков времени выполнения теста, первопричина - особенность асимптотики логарифма на старте

На старте все тесты несколько раз выбивало от трёх секунд, в первую очередь потому что, иногда происходили эти самые пики

Это можно увидеть, если детально рассмотреть сырые данные тестов

Чтобы данные были более-менее полные, и тесты не отваливались от "ложных" пиков - я настроил чувствительность к пикам

Если текущее время выполнения, минус предыдущее - больше чем 0.1 секунды, то текущее время не проверяется на превышение трёх секунд

В таком виде я настроил это для быстрой сортировки, сортировки PHP asort, и моего алгоритма

Но для моего алгоритма - я настроил ещё и отслеживание верхнего предела пика

Если скачок больше 10 секунд - то тест для моего алгоритма дальше выполняться не будет

Дополнительно: быстрая сортировка, смогла пробиться через 3 секунды, из-за какой-то длительной просадки на сервере, и реальное время перевалило за 3 секунды, поэтому тест продолжился

C одной стороны - можно было бы остановить тест, но с другой стороны показательна тенденция на сокращение разрыва, времени выполнения быстрой сортировки и моей при K=2 - поэтому я не прекращал тест, чтобы это было лучше видно

При K=2 и N=3380 - произошёл очередной пик, переваливший за 10 секунд для моего алгоритма (среднее было 8.5 секунд), и я сократил N до 3 500

Потому что дальше соревновались быстрая и asort - мне вместо этого нужно было хоть что-то вразумительное по длительности проведения всех тестов

Подошёл ко второму параметру K

Цикл от 1 до N - слишком просто, в силу особенностей моего алгоритма, поэтому есть ещё один цикл тестирования, который уже цикл самого верхнего уровня, от 0 до K

Где K - ещё одна исследуемая метрика

Изначально это было количество знаков после запятой (сортировка дробных) - как для генерации массива, так и для моего алгоритма сортировки

Но дальше я понял, что эта метрика по сути означает максимальную величину разброса, между минимальным и максимальным значением элементов массива, другими словами - длина пробега второго цикла у моего алгоритма

И длина этого пробега считается по формуле 10^K*abs(max-min)

Формула немного неправильная, потому что K в данном случае определяет эти самые min и max

Но, точнее - непосредственно перед сортировкой, min и max будут изменены, потому что "так надо", по сути - для сортировки дробных чисел

Для массива с диапазоном генерации [-1000;1000] при K=0, максимальная длина пробега составляет 2 000 раз

При K=1 - 20 000 раз

При K=2 - 200 000 раз

При K=3 - 2 000 000 раз

То есть, величина K - означает порядок пробега второго цикла

В принципе эту величину можно подавать дробным числом, и это даже правильней, но у меня уже нет ни желания ни времени на проведение таких тестов

По имеющимся данным и так примерно ясно что к чему

При K=3 и N=2 - время сортировки уже вывалилось за 10 секунд, так как выполнить даже линейный обход двух миллионов позиций - достаточно накладная задача, хоть и 2 миллиона - это теоретический максимум, что там было на практике - я не знаю

Например для [-500,500] это пол миллиона

Данные для K=2 и K=3 из сырых данных - сразу 10+ секунд, на графике видно хоть и плохо

Встроенная сортировка PHP работает быстрее всех, и так же как быстрая сортировка - зависит только от количества элементов

Но по моему графику - видно, что на большом количестве элементов, разрыв с моим алгоритмом сокращается, и возможно что на какой-то дистанции - asort уйдёт в отрыв по времени выполнения

Теперь вернусь к тому, с чего начал, а начал я с того что это вовсе и не сортировка, изначально

Вот список свойств, перечень преимуществ моего алгоритма

1 - свободные элементы последовательности

2 - информация по уникальным/повторяющимся элементам

3 - собственно сортировка, да - тут она как бы бонусом, и на каких-то диапазонах - работает лучше других рассматриваемых алгоритмов

4 - при сортировке именно в таком виде, повторяющиеся элементы сохраняют изначальный порядок следования для случаев, когда сортировать нужно не просто числа, а такие данные, которые должны сохранить уникальность, и это в работе довольно частое явление

5 - для повторяющихся элементов, можно выполнять вложенную сортировку по другим параметрам, без влияния на другие элементы

Первое свойство - точка отсчёта, когда я реализовал этот алгоритм

Второе свойство - возможно где-то нужны подобные данные

Последние два свойства - мне были нужны как раньше, так и в последствии, в моих рабочих задачах

По тех. части

0 - алгоритм ни в коем случае не "универсальный", особенно если говорить о сортировке; слишком много "но"

1 - сами элементы массива опрашиваются только двумя циклами верхнего уровня

2 - вложенный цикл как вспомогательный для компоновки дубликатов, перебора вложениями и рекурсии тут нет

3 - перемещения элементов внутри массива не происходит

4 - скорость как алгоритма сортировки, зависит не только от размера массива, но и от его содержимого

5 - для обработки дробных, необходимо знать предельную точность чисел, и на выходе все дробные будут урезаны до указанной

6 - вычислительная сложность сортировки, по памяти O(2n), по времени O(log(n^k)) в лучшем среднем и худшем случаях

Отдельно про сложность по памяти - тесты на этот счёт я не проводил, поэтому сложность указал умозрительную

O(2n) это для случая, когда нужно сохранить уникальность элементов

Иначе - картина немного другая

O(n+1) в лучшем случае - все элементы повторяются и хранятся в одной ячейке буфера

O(2n) в худшем случае - все элементы уникальны и полностью переносятся в буфер

Плавно подбираюсь к финишу

Я нигде не нашёл ничего похожего с такой же асимптотикой по времени, а она сохраняет свою логарифмичность, по крайней мере это видно на графиках

Для более правильного представления, нужно рисовать трёхмерный график

И этого я уже не умею, а на онлайн сервисах нет возможности этот график повертеть

В экселе тоже можно строить 3D графики, проблема та же самая - нельзя позиционировать "камеру"

Я хотел было показать хоть что-то по этому поводу, но во первых это сложно, во вторых кому "надо" - тот поймёт, или спросит, а я попытаюсь объяснить по другому

Мне же на данном этапе, достаточно того что при наличии степенной зависимости - алгоритм сохраняет логарифмическую составляющую, а значит что на каких-то дистанциях - оставляет за собой право на существование

А учитывая наличие "бонусов" - так и вообще, алгоритм как минимум интересный

Вот вам график для "типовухи", до 1 000 элементов массива и до 1 секунды

Как называется этот алгоритм сортировки ? IT, Программирование, Алгоритм, Сортировка, Исследования, Тестирование, График, Длиннопост

Если пойти дальше, и модифицировать этот алгоритм - можно получить некую вариацию Timsort

Суть идеи в том, что сортировать нужно уже только ключи, любым доступным способом, и даже можно работать с вещественными числами

Но в таком случае - не получится узнать свободные элементы последовательности, а на вещественных числах это может быть даже бессмысленно

Заключение

По описанию - мне что-то напомнило про сортировку Хэна, но при ближайшем рассмотрении - это рокет-сайнс (деревья, хэши, матан)

По сути - чем то похоже на Counting Sort (сортировка количеством), но на практике - количество тут как следствие, а не метод сортировки, само по себе количество нужно очень не всегда, да и чистая Counting Sort в принципе не способна сохранить уникальность и порядок следования, а значит - тоже не то

Оба претендента на сравнение - имеют другие вычислительные сложности

Я не претендую на уникальность, и если такое уже есть - ткните носом

Ещё

Прогуглил пятый вариант названия, как "sparse sort" - нашёл вот что

https://stackoverflow.com/questions/10007463/sorting-in-spar...

Но там по смыслу - не то что у меня, да и тоже что-то сложное

Если всё же такого как у меня, ещё нигде нет - то ну ок, ладно, пользуйтесь

Хоть и не факт что пост вообще стрельнет - уж очень длиннопост получится, плюс специфика вопроса

А я пойду дальше заниматься своими рабочими задачами

P. S. Время проведения тестов - примерно 60 часов процессорного времени, общее время работы - 3 дня с перерывами на другие задачи, и ожидание результатов

Спасибо за внимание

Автор поста оценил этот комментарий
А ты не пробовал запускать алгоритмы на уже отсортированных массивах, только побольше. Прикинуть сколько времени нужно алгоритму чтобы понять что ничего делать не надо?
раскрыть ветку (1)
Автор поста оценил этот комментарий

Думал об этом, но не делал

Умозрительно, по циклам алгоритм просто перенесёт все данные в буфер, вернёт их на место, и если "ничего делать не надо" - данные будут возвращены как были на входе (если опустить некоторые детали про то как работает параметр K)


В целом это всё, что алгоритм делает

В частности - на время выполнения влияет длина пробега второго цикла, min-max, если она очень большая - то время выполнения затянется; не важно выполняется ли при этом сортировка, или нет

По тех. части, сортировки как таковой - в алгоритме нету

перемещения элементов внутри массива не происходит

К слову, сравнения элементов по коду - тоже отсутствуют, только проверка на дубликат, ну и поиск min max

"Магия" с отсортированным массивом на выходе - происходит из-за того, как используются ключи, и как происходит опрос всего массива


В самих тестах я подавал массивы длинной до 10 000 элементов, и в рамках теста, как мне кажется - это не малая величина, относительно конечно

2
Автор поста оценил этот комментарий
Начальный массив для всех алгоритмов должен быть одинаков. Стартовых массивов должно быть несколько, разной степени беспорядка, от 10% и более. На каждом нужно прогнать все алгоритмы сортировки.
раскрыть ветку (1)
Автор поста оценил этот комментарий
Начальный массив для всех алгоритмов должен быть одинаков
Так и есть
Стартовых массивов должно быть несколько
На каждой итерации от 1 до N - массивы всегда разные, значит что количество вариантов массивов - стремится к N

То есть, для N=100 - один массив на 100 элементов, проверяется четырьмя алгоритмами

Для N=500 - один массив на 500 элементов, проверяется четырьмя алгоритмами

разной степени беспорядка, от 10% и более
Степень беспорядка я назвать вам так сходу не могу, но элементы для массива выбираются случайно, приложил скриншот с примерами генерации массивов
На каждом нужно прогнать все алгоритмы сортировки
Так и есть
Иллюстрация к комментарию
показать ответы
1
Автор поста оценил этот комментарий
то что вы делаете, это сортировка подсчетом в чистом виде
раскрыть ветку (1)
Автор поста оценил этот комментарий

Я написал об этом

чем то похоже на Counting Sort (сортировка количеством), но на практике - количество тут как следствие, а не метод сортировки, само по себе количество нужно очень не всегда, да и чистая Counting Sort в принципе не способна сохранить уникальность и порядок следования

И там же про вычислительную сложность

2
Автор поста оценил этот комментарий
Может я не увидел, а насколько перемешан массив массив изначально?
раскрыть ветку (1)
Автор поста оценил этот комментарий

Случайная генерация, то есть перемешан "как ляжет карта"

И генерируется массив каждый раз при увеличении N

В цикле генерируется массив случайных чисел в диапазоне [-1000;1000]
показать ответы