Найти в Дзене
Я, Golang-инженер

#47. Шесть способов сортировки массивов в Go

Оглавление

Это статья об основах программирования на Go. На канале я рассказываю об опыте перехода в IT с нуля, структурирую информацию и делюсь мнением.

UPD: спустя год после публикации, вернулся к этой теме, чтобы пересмотреть алгоритмы сортировки. Обнаружил ошибки в коде, опубликованные в этой статье. Фрагменты кода использовать на свой страх и риск.

Хой, джедаи и амазонки!

В посте я рассказываю о шести способах сортировки массивов/срезов. Показываю примеры кода, а также проверяю длительность работы алгоритмов сортировки с применением пакета "time" на массиве из 100 тысяч интовых элементах.

В конце даётся наглядное сравнение результатов, а ещё некоторые мысли о релевантности подобных экспериментов анализа эффективности алгоритмов.

1. Общая информация

Прохожу в курсе тему алгоритмов сортировки. Нам там дают всего несколько алгоритмов, а я решил копнуть глубже и нашёл много интересного.

Вообще, сортированные массивы (срезы) использовать намного проще, чем несортированные. И процесс сортировки - важный и полезный. Другой вопрос - нужно ли дотошно изучать эти алгоритмы сортировки? Для меня, как практика в первую очередь (я надеюсь им быть), скорее полезно знать - что есть разные алгоритмы сортировки, и одни эффективнее других.

1.1. Применение сортированных массивов

Где применяются сортированные массивы? В базах данных, а это:

  1. Социальные сети: с использованием сортированных массивов можно легко и быстро отсортировать список друзей по алфавиту, по количеству друзей, по дате последнего визита и т.д. Это делает поиск нужных контактов более удобным и быстрым.
  2. Телефонные книги: в телефонных книгах используются сортированные массивы, чтобы быстро найти нужный контакт. Контакты могут быть отстированы по имени, фамилии, номеру телефона или по любым другим параметрам.
  3. Поиск в интернете: при поиске информации в интернете сортированные массивы используются для быстрого и эффективного поиска. Например, при поиске товаров в интернет-магазине можно отсортировать их по цене, рейтингу, бренду и т.д.

А ещё сортированные массивы применяют в алгоритмах сжатия данных: такие алгоритмы позволяют уменьшить размер данных, не теряя при этом информации. Например, сортированные массивы могут использоваться для устранения повторяющихся значений в данных.

В целом, сортированные массивы - это мощный инструмент для обработки и хранения данных во многих областях IT. Они ускоряют работу с данными и позволяют быстро находить нужную информацию.

Вот какие они полезные - сортированные массивы.

1.2. Виды сортированных массивов

Какие я рассмотрю в этой статье способы:

  1. Cортировка пузырьком - O(n^2).
  2. Cортировка выбором - O(n^2).
  3. Cортировка вставками O(n^2).
  4. Быстрая сортировка - O(n x log n).
  5. Сортировка слиянием - O(n x log n).

В списке я использовал О-большое. Что это такое? Можно о нём почитать, например, здесь.

Я в этой статье нашёл интересную тезу:

В задачах на программирование самое сложное и интересное — попытаться обойтись простым циклом, без вложенного, или даже вообще без цикла.

Мне сразу вспомнилась задача на написание кода "ёлочка". Там я рассчитывал ширину основания ёлочки по высоте: сперва циклом, затем - формулой. Это типичный пример, как без цикла можно решить некоторые задачи.

Далее поехали разбираться с кодом.

2. Алгоритмы сортировки

Сперва мы создаём массив с использованием генератора случайных чисел. Ничего необычного.

Создаём массив
Создаём массив

В строке 19 указан размер массива - почему 100 000? Да просто так, методом тыка - чтобы алгоритмы прокачали "железо" более-менее, а не выполнились за одну триллионную долю секунды, или наоборот - не нагрузили.

Чтобы следовать принципам чистого кода, я стараюсь разбивать код на смысловые функции. И обеспечить, чтобы функции выполняли только что-то одно, а не множество различных действий.

Вот тут я обнаружил интересную штуку:

В Go вернуть массив произвольной длины из функции невозможно. Для этого используют срезы: массивы применяют редко, но о них нам полезно знать, т.к. срезы содержат в себе массивы.

Суть в чём - вернуть из функции массив, для которого длина задана константой - можно. Но я не хочу использовать глобальные (и любые другие) константы, а, например - иметь возможность ввести длину массива с консоли.

Это база - дальше к ней цепляем алгоритмы.

2.1. Сортировка пузырьком

В функцию main() дописываем код:

Фрагмент кода
Фрагмент кода

И такой фрагмент - функция сортировки пузырьком:

Функция сортировки пузырьком
Функция сортировки пузырьком

Что здесь интересного?

  • В стоке 15 я создал пустой массив той же длины, как и созданный ранее с сгенерированными случайным образом числами.
  • В строке 17 я использую функцию копирования значений массива с сгенерированными элементами в массив с нулевыми элементами. Это необходимо, чтобы при сортировке последующими алгоритмами мы продолжили использовать исходный массив, а не его отсортированную версию.
  • Строка 18 и 20 даёт нам разницу во времени между операцией.

Результаты пока не показываю, скажу только - что это самый примитивный алгоритм из рассмотренных. В том плане, что самый медлительный.

2.2. Сортировка выбором

Код в main():

Код
Код

Алгоритм:

Код
Код

2.3. Сортировка вставками

Код в main():

Код
Код

Алгоритм сортировки

Код
Код

2.4. Быстрая сортировка

Код в main():

Код
Код

Алгоритм сортировки:

Код
Код

2.5. Сортировка слиянием

Код в main():

Код
Код

Алгоритм сортировки:

Код
Код

2.6. Встроенная в Go сортировка

Код в main():

Код
Код

Скажу так - это самый шустрый алгоритм сортировки. Что он содержит под собой? Коллеги говорят, что там аналог PD-quicksort, наподобие описанного здесь <<<

Фрагмент статьи по ссылке о PD-быстрой сортировке
Фрагмент статьи по ссылке о PD-быстрой сортировке

Только алгоритм сортировки Go без Block-quicksort-оптимизации.

Теперь поехали разбираться с производительностью алгоритмов.

3. Производительность алгоритмов

Полный код всех шести алгоритмов можно посмотреть на моём GitHub'e. Ниже реализация кода на моём "железе".

Первое выполнение кода
Первое выполнение кода

Далее повторил go run... и вот что вышло:

Второе выполнение кода
Второе выполнение кода

Как видим, данные разнятся. Плюс-минус результаты похожи, но тем не менее. Попробуем ещё разок:

Третье выполнение кода
Третье выполнение кода

Как видим, результат разнится уже не плюс-минус, а в два раза для времени выполнения алгоритма сортировки, встроенного в Go. В чём дело?

А дело в том, что у нас многозадачные и многопоточные операционные системы, что даёт большую погрешность для измерения. В значительной степени этот недостаток помогает компенсировать пакет "testing" с его бенчмарками.

Режим бенчмарк "гоняет" функцию в течение заранее заданного периода времени (если функция быстрая — миллиард раз, а то и больше), и усредняет полученные значения.

У меня нет сейчас большого желания разбираться с бенчмарками. Я сделаю проще - соберу среднее арифметическое из трёх значений и визуализирую информацию для ориентировочного понимания скорости работы алгоритмов:

График анализа алгоритмов
График анализа алгоритмов

4. Выводы

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

Самое главное, что нужно усвоить на мой взгляд - что можно сортировать массивы различными способами. И встроенный алгоритм сортировки в Go - очень мощный, примерно вдвое мощнее "Быстрой сортировки" или "сортировки вставками".

Чисто ради любопытства - проделаем анализ для массива длиной 100. Результаты:

-18

Как видим, для маленьких массивов пьедестал для алгоритмов по сортировке изменился. Тоже полезно об этом знать - для больших массивов очень эффективна встроенная в Go сортировка, а для малых может быть выгодна другая сортировка.

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

--//--//--

PS Если захочешь купить курс от SkillBox, воспользуйся моей реферальной ссылкой. Ты получишь огромную скидку на курс и плюс в карму за помощь каналу.

Кста, курс Go-разработчик, по-видимому ушёл на глубокую доработку в SkillBox, т.к. его уже нет в продаже :) Намана, курс развивается.

 Markus Spiske Available for hire https://unsplash.com/photos/uPXs5Vx5bIg
Markus Spiske Available for hire https://unsplash.com/photos/uPXs5Vx5bIg

Бро, ты уже здесь? 👉 Подпишись на канал для новичков «Войти в IT» в Telegram, будем изучать IT вместе 👨‍💻👩‍💻👨‍💻