Подборка алгоритмов для изучения языка Python
Изучение алгоритмов и понимание заложенных в них принципов работы является неотъемлемой частью обучения. Многие алгоритмы уже реализованы в библиотеках, но для оптимизации скорости выполнения или добавление признаков важно знать, что находится «под капотом» и как реализовать что-то с нуля. Рассмотрим алгоритмы с такой структурой данных как списки: квадратичные сортировки и сортировки, работающие по принципу, разделяй и властвуй, а также проверку на отсортированность списка.
Все сортировки будем тестировать на одним и тех же входных данных. Сгенерируем список и используем метод shuffle встроенной библиотеки random:
Для определения времени выполнения сортировки в jupyter notebook нужно указать в начале ячейки магический метод %%time либо воспользуйтесь декоратором для .py расширения:
Перед каждой функцией, время выполнения которой вы хотите вычислить добавьте строчку:
Квадратичные сортировки
Количество операций, которое требуется для сортировки примерно O(N**2).
Про big O notation можно почитать здесь.
Сортировка списка вставками
Время выполнения сортировки: 6.79 сек.
Инвариант у каждой сортировки свой. Принцип работы сортировки вставками: проверяем элементы слева-направо начиная со второго и смотрим больше ли он предыдущего, если да, оставляем на месте, если элемент меньше предыдущего, берем его и тащим налево до тех пор, пока не встретим элемент меньше, чем он.
Сортировка списка выбором
Время выполнения сортировки: 5.04 сек.
Первый элемент в начальной позиции принимаем за самый маленький и бежим по списку слева направо и ищем того, кто меньше его, когда нашли меняем местами, дальше уже не смотрим на первую позицию считая, что элемент уже на своем месте (этот момент реализован в цикле как — начни с range(pos+1, N) и так с каждым кроме последнего, т.к. он сам окажется на своем месте.
Пузырьковая сортировка списка
Время выполнения сортировки: 7.42 сек.
Производится проход по списку слева направо и, если текущий элемент меньше предыдущего, то они меняются местами. Таким образом самый большой элемент подобно пузырьку всплывет в самую последнюю позицию. Далее, используя отсечение в цикле N-bybass, исключаем возможность проверки тех элементов, которые уже “всплыли наверх”.
Превосходное объяснение работы сортировок вы можете посмотреть в лекции.
Рекуррентные сортировки
Быстрая сортировка и сортировка слиянием работает по принципу “разделяй и властвуй”. В отличие от квадратичных сортировок они выполняются с логарифмической сложностью.
Сортировка Тома Хоара (Quick sort)
Обычно на случайных выборках она работает W(N *log2N), а иногда O(N**2). Сортирующие действия выполняются на прямом ходу рекурсии. Дополнительная память не требуется.
Делаем явную копию списка numbers т.к. сортировка изменяет входной список напрямую:
Сортировка:
Время выполнения сортировки: 0.30 сек.
Берем первый элемент и считаем его барьером, далее сортируем список, т.е. те, кто меньше его, идут в левый список, те, кто больше, идут в правый список, а равные ему идут в средний список. Передаем каждый наш фрагмент снова в функцию, тем самым реализовав рекурсию, пока не сработает крайний случай, что значит длина списка равна единице или нулю, и далее соединяем три получившихся части: L, M, R в список A.
Сортировка слиянием
На любых входных данных работает O(N*log2N). Сортировка выполняется на обратном ходу рекурсии. Требуется дополнительная память.
Время выполнения сортировки: 0.60 сек.
Как выполняется сортировка: рекурсивно делим списки пополам на левую и правую части, далее, встретив крайний случай (длина списка <=1) на обратном ходу рекурсии, эти пары половинок попадают в функцию merge. В ней сначала создается новый список С, в который далее вливаются значения из половинок слева направо. Функция merge возвращает список С, значения которого уже в отсортированном виде попадают в цикле в список А.
Проверка того, что список отсортирован за O(len(A))
Если встречается элемент, который больше следующего, то происходит выход из цикла с флагом False.
Сортировка Тома Хоара получилась быстрее сортировки слиянием в два раза, но иногда в зависимости от входных данных может работать дольше. Сортировка слиянием в свою очередь требует дополнительную память, что, например, при слишком больших входных данных может стать узким местом.
Очень полезная публикация! Спасибо автору!
Спасибо !