Компьютерные алгоритмы – сортировки
Поговорим про алгоритмы сортировки данных.
В прошлой серии мы говорили про Big O нотацию и бинарный поиск.
Давайте сегодня посмотрим на алгоритмы сортировок — без них в CS никуда.
Прежде чем начать про них разговор, давай разберемся с таким понятием, как рекурсия.
Почему-то некоторых она сильно пугает, однако – это очень простое понятие, которое легче всего иллюстрируется любимым фильмом.
Все очень просто — пока выполняется некое условие, функция вызывает сама себя. Когда условие не выполняется - код перестает себя вызывать и делает что-то другое.
Если искать примеры в реальной жизни, то в качестве рекурсии можно в пример привести чулан, который наполнен коробками из Ikea. У них есть совершенно разные коробки - большие, средние, маленькие, очень маленькие, и очень-очень маленькие. Представьте, вам нужно найти пару носок, которые были подарены на гендерный праздник 5 лет назад и в тот же день убраны в чулан. За 5 лет было много уборок, перестановок и пара переездов поэтому маленькую коробку с носками положили в коробку побольше, а коробку побольше в совсем большую. Открываете чулан, перед вами полдюжины одинаковых коробок. Что делать ? Правильно, начинать с первой большой коробки, и смотреть все внутри нее. Когда в первой большой коробке всё посмотрели - смотрим следующую большую. И так пока коробки не закончатся или не будут найдены носки. Как только носки найдены - задача достигнута.
А вот пример кодом - скажем, посчитаем от числа N до 0. Как только досчитали до нуля - пишем в консоль «Танцуют все!👯♀»
Выполнив функцию, увидем в консоле такое:
При первом вызове функции, она вызывается с аргументом «5». Зайдя в тело функции, if выражение видит, что count не равен 0, он равен 5. А раз так, то функция вызывает сама себя, вычитая из 5 цифру 1. И все это повторяется, пока мы не досчитали до 0.
И это вся рекурсия.
Самое главное - когда будете писать, не забывайте об условии выхода из рекурсии. В моем примере это countsLeft == 0.
Теперь к алгоритмам сортировок.
Selection sort.
Это очень простая сортировка. Мы часто пользуемся ей в реальной жизни - например, когда играем в пятикарточный покер или червы. Держа в руке карты, всегда начинаешь инстинктивно сортировать их в руке, чтобы увидеть комбинацию.
Давайте на коде.
Шаг первый
Объявляем переменную minimum. В нее кладем самый первый элемент массива, те 15.
Шаг второй
Сравниваем минимум с элементом, который идет следующим после минимума. Следующий - второй.
Если следующий элемент меньше - делаем его минимумом.
Повторяем процедуру сравнения минимума со следующим элементом, пока не дойдем до конца массива.
Как только дошли до конца массива - кладем минимум в самое начало массива.
Делаем повтор первого и второго шагов для следующего элемента массива.
Сортируем массив [-2, 45, 11, 0, -9]
Расставляем принты, смотрим результат
Selection sort делает (n - 1) + (n - 2) + (n - 3) + ..... + 1 = n(n - 1) / 2 сравнений что примерно получается n в квадрате.
Таким образом его сложность - O(n²)
Insertion sort
Представьте, что у вас магазин мужских костюмов. Каждую среду поставщик привозит несколько новых костюмов, которые нужно выставить на витрину. Как только их привезли - логично будет их повесить сразу, чтобы они не собирали пыль. Повесив их на витрину к уже продающимся, у вас получается 2 части костюмов - новые, не сортированные по размеру, и те, которые уже были раньше - они висят в правильном порядке. Дальше берете каждый новый костюм и двигаете его в нужное место.
А шаги для имплементации алгоритма будут следующие:
- Проходимся циклом по всем элементам массива, начиная с array[1] до конца массива.В начале каждого цикла объявляем ключом текущий элемент
- Если ключ меньше, чем элемент перед ним, то продвигаем предыдущий элемент на одну позицию вперед.
Слоумо алгоритма.
И иллюстрация работы алгоритма в исполнении румынского ансамбля.
Сложность алгоритма зависит от состояния данных.
Если массив уже отсортирован, то сложность будет O(n) - тк надо будет пробежаться по каждому объекту.
Если массив не сортирован, то сложность будет n*(n-1) что приблизительно равно n², те O(n²)
Merge Sort
Мы добрались до алгоритма, который использует рекурсию. Merge Sort - построен на базе алгоритма Divide and Conquer, у него логика следующая - проблема последовательно упрощается до состояния, с которым работать проще всего. Так называемый базовый кейс.
На примере Merge Sort это работает так - исходный массив разбивается на небольшие массивы, а каждый небольшой массив разбивается до тех пор, пока в массиве не останется 1 объект.
Для Merge Sort массив длинной в один объект как раз и является базовым кейсом. Дальше алгоритм Merge Sort сравнивает результаты и мержит их.
Лучше всего его работу проиллюстрирует картинка.
Код
Сложность Merge Sort – O(n*log n).
В следующих сериях поговорим, как выбирать алгоритм сортировки.
Сегодня все. Stay tuned!