Перечислите основные алгоритмы сортировки и их временную сложность

Ответ

Существует множество алгоритмов сортировки, различающихся по эффективности, требованиям к памяти и стабильности. Вот основные из них:

  1. Сортировка пузырьком (Bubble Sort)

    • Принцип: Многократно проходит по массиву, сравнивая соседние элементы и меняя их местами, если они стоят в неверном порядке. Самые "тяжелые" элементы "всплывают" в конец.
    • Сложность: O(n²)
    • Особенности: Прост для понимания, но крайне неэффективен на больших данных.
  2. Сортировка выбором (Selection Sort)

    • Принцип: Находит минимальный элемент в неотсортированной части массива и ставит его в начало.
    • Сложность: O(n²)
    • Особенности: Нестабильный, но делает минимальное количество обменов.
  3. Быстрая сортировка (Quick Sort)

    • Принцип: Использует подход "разделяй и властвуй". Выбирается опорный элемент (pivot), и массив делится на две части: элементы меньше опорного и элементы больше опорного. Процесс рекурсивно повторяется для каждой части.
    • Сложность: В среднем O(n log n), в худшем случае O(n²).
    • Особенности: Один из самых быстрых алгоритмов на практике, но нестабильный.
  4. Сортировка слиянием (Merge Sort)

    • Принцип: Также использует "разделяй и властвуй". Массив рекурсивно делится пополам до тех пор, пока не останутся единичные элементы, а затем отсортированные части сливаются обратно.
    • Сложность: O(n log n) в любом случае.
    • Особенности: Стабильный, но требует дополнительной памяти O(n) для слияния.
  5. Timsort

    • Принцип: Гибридный алгоритм, сочетающий сортировку слиянием и сортировку вставками. Эффективно работает на частично отсортированных данных.
    • Сложность: O(n log n) в худшем случае, O(n) в лучшем.
    • Особенности: Это стандартный алгоритм сортировки в Python (list.sort(), sorted()).
Алгоритм Средняя сложность Худшая сложность Доп. память Стабильность
Пузырьковая O(n²) O(n²) O(1) Да
Выбором O(n²) O(n²) O(1) Нет
Быстрая O(n log n) O(n²) O(log n) Нет
Слиянием O(n log n) O(n log n) O(n) Да
Timsort O(n log n) O(n log n) O(n) Да

Ответ 18+ 🔞

Э, слушай, вот сидишь ты такой, пишешь свой код, и тут бац — надо это всё отсортировать. А алгоритмов-то, блядь, овердохуища! И все они как мартышлюшки: одни быстрые, другие тупые, третьи память жрут, как не в себя. Давай разберём эту пиздопроебибну по полочкам, а то голова пухнет.

Ну вот, например, сортировка пузырьком. Это ж классика жанра, ёпта! Представь: массив — это твои друзья после пятницы в баре. Самый пьяный (самый большой элемент) постоянно норовит впердолиться в конец очереди за шаурмой. Его туда-сюда толкают, пока он не упрётся в стенку. Простота — хуй с горы, но работает она, блядь, как черепаха в сиропе — O(n²). На маленьком списке покумекать можно, а на тысяче элементов — лучше повеситься.

def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]

Дальше — сортировка выбором. Хитрая жопа. Она бегает по неотсортированной части, ищет самого мелкого пид... то есть, минимальный элемент, и ставит его в начало. "Ты — самый маленький, стой первым!" И так раз за разом. Тоже O(n²), но обменов делает мало. Зато стабильности — ноль ебать, может равные элементы перепутать, мудя.

А теперь держись за стул — быстрая сортировка (Quick Sort). Вот это, блядь, зверь! Берёт какой-нибудь элемент (pivot), и всех, кто меньше него — налево, а кто больше — направо. Потом рекурсивно делает то же самое с каждой кучей. В среднем — красота, O(n log n), скорость — огонь. Но если не повезёт с опорным элементом, может скатиться в O(n²), и тогда пидарас шерстяной. И тоже нестабильная, да.

def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)

Сортировка слиянием — это уже интеллигент в очках. Делит массив пополам, пока не дойдёт до одиночных элементов, а потом аккуратно склеивает их обратно, но уже в порядке возрастания. Стабильная, надёжная, всегда O(n log n). Но, сука, требует дополнительной памяти для этого своего клея — O(n). Не жадная, но и не экономная.

И наконец, король современных подмостков — Timsort. Это гибрид, помесь слияния с вставками. Умный, как чёрт, особенно на частично упорядоченных данных. В худшем случае O(n log n), а если данные почти готовы — так вообще O(n). Это, на минуточку, стандартный сортировщик в Python! Когда пишешь sorted(my_list) — под капотом работает этот красавец. Стабильный, быстрый, просто ебать мои старые костыли.

Вот тебе табличка, чтобы не запоминать эту хуйню, а просто тыкать пальцем:

Алгоритм Средняя сложность Худшая сложность Доп. память Стабильность
Пузырьковая O(n²) O(n²) O(1) Да
Выбором O(n²) O(n²) O(1) Нет
Быстрая O(n log n) O(n²) O(log n) Нет
Слиянием O(n log n) O(n log n) O(n) Да
Timsort O(n log n) O(n log n) O(n) Да

Короче, если не хочешь заморачиваться — используй встроенную сортировку, там умные люди всё уже придумали. А если на собеседовании спросят — теперь будешь знать, что рассказать, кроме "ну, там sorted() вызываю, и всё работает".