Алгоритмы сортировки в Python с примерами кода

Раздел: Алгоритмы -> Алгоритмы сортировки

Примеры сортировки в Python: от простых решений до специализированных алгоритмов

Как отсортировать список в Python с максимальной производительностью и минимальным объёмом кода?

Наиболее эффективным средством является встроенная функция sorted() и метод списка sort(). Оба реализуют алгоритм Timsort (гибрид сортировки слиянием и вставками), работающий за O(n log n) в худшем случае и O(n) на частично упорядоченных данных. sorted() возвращает новый отсортированный список, не изменяя исходный. sort() изменяет список на месте и возвращает None.


# sorted() возвращает новый список
nums = [3, 1, 4, 1, 5, 9]
sorted_nums = sorted(nums)
print(sorted_nums)   # [1, 1, 3, 4, 5, 9]
print(nums)          # [3, 1, 4, 1, 5, 9] - исходный не изменился

# sort() изменяет исходный список
nums.sort()
print(nums)          # [1, 1, 3, 4, 5, 9]
  

алгоритмы сортировки python (алгоритмы сортировки в python)

[1, 1, 3, 4, 5, 9]
[3, 1, 4, 1, 5, 9]
[1, 1, 3, 4, 5, 9]
  

сортировка python примеры (примеры сортировки в python)

Типичная ошибка: попытка отсортировать список, содержащий элементы разных типов (например, числа и строки). Python вызовет TypeError, так как не может сравнить int и str. Решение: либо привести все элементы к единому типу, либо использовать параметр key для преобразования (например, key=str).


# Ошибка
# sorted([1, 'two', 3])  # TypeError

# Исправление: преобразуем все в строки
sorted([1, 'two', 3], key=str)  # [1, 3, 'two']
    

быстрая сортировка python (реализация быстрой сортировки на python)

Параметры reverse (для изменения порядка на обратный) и key (для задания функции, вычисляющей ключ сортировки) делают эти методы универсальными.

Как реализовать сортировку пузырьком для учебных целей?

Сортировка пузырьком (Bubble sort) многократно проходит по списку, сравнивая соседние элементы и меняя их местами, если они стоят в неправильном порядке. Процесс повторяется до тех пор, пока не будет выполнена полная сортировка. Сложность O(n²) – медленный алгоритм, полезный только для обучения.


def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        # Флаг, чтобы отследить, были ли обмены на текущем проходе
        swapped = False
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
                swapped = True
        if not swapped:
            break
    return arr

arr = [64, 34, 25, 12, 22, 11, 90]
print(bubble_sort(arr[:]))  # [11, 12, 22, 25, 34, 64, 90]
  

сортировка выбором python (сортировка выбором в python)

[11, 12, 22, 25, 34, 64, 90]

сортировка данных python (сортировка данных в python)

Проблема: без оптимизации (флага) алгоритм выполняет лишние проходы даже на уже отсортированном массиве. Также при большом количестве элементов время выполнения становится неприемлемым. Рекомендуется использовать только на маленьких наборах данных (до нескольких сотен элементов).

Как отсортировать список в обратном порядке с помощью встроенных средств?

Достаточно указать параметр reverse=True в sorted() или sort().


sorted(nums, reverse=True)   # [9, 5, 4, 3, 1, 1]
nums.sort(reverse=True)
  

Ошибка: путаница между reverse и key. Параметр reverse просто переворачивает порядок после сортировки по возрастанию. Если нужно сортировать по убыванию, но с особым ключом, используйте оба параметра.

Как отсортировать список словарей по значению определённого поля?

Применяется key с lambda-функцией, извлекающей нужное поле.


students = [
    {'name': 'Alice', 'grade': 88},
    {'name': 'Bob', 'grade': 95},
    {'name': 'Charlie', 'grade': 72}
]
sorted_by_grade = sorted(students, key=lambda s: s['grade'])
print(sorted_by_grade)
  
[{'name': 'Charlie', 'grade': 72}, {'name': 'Alice', 'grade': 88}, {'name': 'Bob', 'grade': 95}]
  

Типичная ошибка: если у какого-то словаря отсутствует ключ, возникнет KeyError. Используйте dict.get() с значением по умолчанию в лямбде.


sorted_by_grade = sorted(students, key=lambda s: s.get('grade', 0))
    

Как реализовать быструю сортировку (Quick sort) на Python?

Быстрая сортировка выбирает опорный элемент (pivot), разбивает массив на элементы меньше и больше pivot, затем рекурсивно сортирует две части. Средняя сложность O(n log n), но в худшем случае (например, уже отсортированный массив с неудачным выбором pivot) может деградировать до 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)

arr = [3, 6, 8, 10, 1, 2, 1]
print(quick_sort(arr))
  
[1, 1, 2, 3, 6, 8, 10]

Проблема: рекурсивная версия может вызвать переполнение стека при очень больших списках (глубина рекурсии ~ log n, но в худшем случае n). Альтернатива - итеративная реализация с явным стеком. Также копирование списков (list comprehensions) увеличивает расход памяти. Для производственного кода лучше использовать встроенную сортировку.

Как выполнить сортировку слиянием (Merge sort) на Python?

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


def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    return merge(left, right)

def merge(left, right):
    result = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result

arr = [38, 27, 43, 3, 9, 82, 10]
print(merge_sort(arr))
  
[3, 9, 10, 27, 38, 43, 82]

Ошибка: неверная обработка границ при слиянии (выход за пределы списка). Важно проверять индексы i и j. Также рекурсивная версия требует много памяти для хранения копий. Для больших данных предпочтительна итеративная реализация.

Как отсортировать список, используя пользовательский класс с методом __lt__?

Если нужно сортировать объекты пользовательского типа, можно определить в классе метод __lt__(self, other), который возвращает True, если self должен быть меньше other. Тогда sorted() будет использовать его.


class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __lt__(self, other):
        return self.age < other.age
    def __repr__(self):
        return f'{self.name}({self.age})'

people = [Person('Alice', 30), Person('Bob', 25), Person('Charlie', 35)]
print(sorted(people))
  
[Bob(25), Alice(30), Charlie(35)]

Предостережение: если в классе не определен __lt__, Python не сможет сравнить объекты, и sorted() выдаст TypeError. Всегда стоит явно определять хотя бы один из операторов сравнения (__lt__, __gt__ и т.д.) или использовать параметр key.

Как отсортировать список по нескольким критериям?

Можно вернуть кортеж из нескольких ключей в lambda. Сортировка будет выполняться сначала по первому элементу кортежа, затем при равенстве по второму и т.д.


data = [('Alice', 25, 85), ('Bob', 22, 90), ('Alice', 22, 92)]
sorted_data = sorted(data, key=lambda x: (x[0], -x[1], x[2]))
print(sorted_data)
  
[('Alice', 25, 85), ('Alice', 22, 92), ('Bob', 22, 90)]

В примере сначала по имени (по возрастанию), затем по возрасту (убывание за счёт минуса).

Какие проблемы возникают при сортировке строк с учётом регистра?

По умолчанию строки сортируются по лексикографическому порядку на основе кодов Unicode. Заглавные буквы имеют меньшие коды, чем строчные, поэтому 'Apple' окажется раньше 'apple'. Чтобы игнорировать регистр, используется key=str.lower.


words = ['banana', 'Apple', 'cherry', 'Banana']
sorted(words)              # ['Apple', 'Banana', 'banana', 'cherry']
sorted(words, key=str.lower)  # ['Apple', 'banana', 'Banana', 'cherry']
  

Проблема: str.lower работает не для всех локалей (например, турецкий 'İ'). Для корректной международной сортировки используйте модуль locale с locale.strxfrm.

Расширенные примеры сортировки в Python

Пример 1. Сортировка списка кортежей по нескольким полям с использованием itemgetter

Модуль operator предоставляет функцию itemgetter, которая может быть быстрее lambda при сортировке по фиксированным индексам или ключам.

Пример

from operator import itemgetter

data = [(2, 'Alice', 25), (1, 'Bob', 30), (2, 'Charlie', 20)]
sorted_data = sorted(data, key=itemgetter(0, 2))  # сначала по первому полю, затем по третьему
print(sorted_data)
  
[(1, 'Bob', 30), (2, 'Alice', 25), (2, 'Charlie', 20)]
  

Обратите внимание: itemgetter(0, 2) возвращает кортеж (элемент[0], элемент[2]).

Пример 2. Сортировка списка объектов с помощью attrgetter

operator.attrgetter извлекает атрибуты объекта по имени.

Пример

from operator import attrgetter

class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
    def __repr__(self):
        return f'{self.name}:${self.salary}'

emps = [Employee('John', 50000), Employee('Jane', 60000), Employee('Dave', 50000)]
sorted_emps = sorted(emps, key=attrgetter('salary', 'name'))
print(sorted_emps)
  
[Dave:$50000, John:$50000, Jane:$60000]
  

Пример 3. Итеративная быстрая сортировка (без рекурсии)

Используется стек для имитации рекурсии, что позволяет избежать переполнения стека при очень больших массивах.

Пример

def quick_sort_iterative(arr):
    if len(arr) <= 1:
        return arr
    stack = [(0, len(arr)-1)]
    result = arr[:]  # копия
    while stack:
        low, high = stack.pop()
        if low < high:
            pivot = result[(low + high) // 2]
            left = low
            right = high
            while left <= right:
                while result[left] < pivot:
                    left += 1
                while result[right] > pivot:
                    right -= 1
                if left <= right:
                    result[left], result[right] = result[right], result[left]
                    left += 1
                    right -= 1
            stack.append((low, right))
            stack.append((left, high))
    return result

arr = [7, 2, 1, 6, 8, 5, 3, 4]
print(quick_sort_iterative(arr))
  
[1, 2, 3, 4, 5, 6, 7, 8]

Пример 4. Сортировка с помощью heapq.nlargest и nsmallest

Если требуется получить только несколько наибольших или наименьших элементов, не сортируя весь список, эффективно использовать модуль heapq.

Пример

import heapq

numbers = [10, 3, 5, 7, 9, 2, 4, 6, 8, 1]
three_largest = heapq.nlargest(3, numbers)
three_smallest = heapq.nsmallest(3, numbers)
print(three_largest)   # [10, 9, 8]
print(three_smallest)  # [1, 2, 3]
  
[10, 9, 8]
[1, 2, 3]
  

Сложность O(n log k), где k - количество запрашиваемых элементов.

Пример 5. Сортировка строк с использованием натурального порядка (Natural sort)

Для сортировки строк, содержащих числа (например, 'file1.txt', 'file10.txt'), стандартная лексикографическая сортировка даёт неверный порядок. Решение - разделять строку на буквенные и числовые части и сравнивать числовые как int.

Пример

import re

def natural_key(s):
    return [int(text) if text.isdigit() else text.lower() 
            for text in re.split(r'(\d+)', s)]

files = ['file10.txt', 'file2.txt', 'file1.txt', 'file20.txt']
sorted_files = sorted(files, key=natural_key)
print(sorted_files)
  
['file1.txt', 'file2.txt', 'file10.txt', 'file20.txt']
  

Пример 6. Сортировка с использованием functools.cmp_to_key (старый стиль)

Если определена функция сравнения, возвращающая -1, 0, 1, можно преобразовать её в ключ с помощью functools.cmp_to_key. Этот способ рекомендуется только для совместимости с Python 2.

Пример

from functools import cmp_to_key

def compare(a, b):
    if a < b:
        return -1
    elif a > b:
        return 1
    else:
        return 0

nums = [3, 1, 4, 1, 5, 9]
sorted_nums = sorted(nums, key=cmp_to_key(compare))
print(sorted_nums)
  
[1, 1, 3, 4, 5, 9]

Современный подход - использовать key с преобразованием.

Пример 7. Проверка, отсортирован ли список

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

Пример

def is_sorted(lst, key=lambda x: x):
    return all(key(lst[i]) <= key(lst[i+1]) for i in range(len(lst)-1))

print(is_sorted([1, 2, 3]))          # True
print(is_sorted([3, 2, 1]))          # False
print(is_sorted(['a', 'B'], key=str.lower))  # True (если игнорировать регистр)
  
True
False
True
  

Пример 8. Сортировка списка списков по вложенному значению

Если есть список списков (матрица), и нужно отсортировать внешний список по сумме или по конкретному столбцу.

Пример

matrix = [[9, 2, 3], [4, 5, 6], [7, 8, 1]]
sorted_by_sum = sorted(matrix, key=sum)
sorted_by_last = sorted(matrix, key=lambda row: row[-1])
print('По сумме:', sorted_by_sum)
print('По последнему элементу:', sorted_by_last)
  
По сумме: [[4, 5, 6], [7, 8, 1], [9, 2, 3]]
По последнему элементу: [[7, 8, 1], [9, 2, 3], [4, 5, 6]]
  

Примеры сортировки в Python - comments

En
сортировка python примеры (python)