🐘 PHP

Sortieralgorithmen in PHP: Eine ausführliche Anleitung

Что это такое и зачем? (аналогия из реальной жизни)

Представьте, что вы — библиотекарь, и у вас есть огромная стопка книг, которые нужно расставить на полки в алфавитном порядке. Если книг всего пять, вы сделаете это за минуту. Но что, если книг тысяча? Или десять тысяч? Вы будете перебирать их вручную, тратить часы и обязательно ошибётесь.

Алгоритм сортировки — это чёткая, пошаговая инструкция для компьютера, которая говорит ему: «Возьми этот список чисел (или слов, или любых других данных) и расположи их в правильном порядке: от меньшего к большему или по алфавиту». Компьютер, в отличие от человека, не устаёт, не отвлекается и делает всё строго по инструкции.

В реальной жизни мы постоянно сталкиваемся с сортировкой:

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

Без сортировки современный мир просто не смог бы работать. Базы данных, поисковые системы, социальные сети — всё это использует сортировку миллионы раз в секунду.

Важно: Сортировка — это не просто «красивое расположение». Это основа для быстрого поиска. Если данные не отсортированы, чтобы найти нужный элемент, придётся просмотреть ВСЕ данные. Если они отсортированы, можно использовать бинарный поиск, который работает в сотни раз быстрее.

Теория: как это работает изнутри

Давайте заглянем «под капот» и разберёмся, как компьютер выполняет сортировку. Представьте, что у нас есть массив чисел: [5, 3, 8, 1, 9, 2]. Наша цель — получить [1, 2, 3, 5, 8, 9].

Существуют десятки алгоритмов сортировки, но все они делятся на несколько основных типов. Мы рассмотрим три самых популярных и понятных:

1. Пузырьковая сортировка (Bubble Sort) — «метод пузырька»

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

Как это работает:

  1. Берём первый элемент (5) и сравниваем со вторым (3). 5 > 3? Да. Меняем их местами. Теперь: [3, 5, 8, 1, 9, 2].
  2. Сравниваем второй (5) с третьим (8). 5 > 8? Нет. Оставляем как есть.
  3. Сравниваем третий (8) с четвёртым (1). 8 > 1? Да. Меняем: [3, 5, 1, 8, 9, 2].
  4. Продолжаем так до конца массива. После первого полного прохода самый большой элемент (9) «всплывает» в конец, как пузырёк в газировке. Отсюда и название.
  5. Повторяем всё сначала, но уже не трогаем последний элемент (он уже на месте).

Этот алгоритм делает очень много лишних сравнений, поэтому для больших массивов он непригоден.

2. Сортировка выбором (Selection Sort) — «метод выбора»

Представьте, что вы раскладываете карты в руке по возрастанию. Вы ищете самую маленькую карту и кладёте её первой. Потом ищете следующую самую маленькую среди оставшихся и кладёте второй. И так далее.

Как это работает:

  1. Ищем минимальный элемент во всём массиве. Это 1 (на позиции 4).
  2. Меняем его местами с первым элементом (5). Получаем: [1, 3, 8, 5, 9, 2].
  3. Теперь ищем минимальный элемент в оставшейся части (начиная со второго). Это 2 (на последней позиции).
  4. Меняем его со вторым элементом (3). Получаем: [1, 2, 8, 5, 9, 3].
  5. Повторяем, пока не дойдём до конца.

Этот алгоритм делает меньше перестановок, чем пузырьковый, но всё равно много сравнений.

3. Быстрая сортировка (Quick Sort) — «король сортировки»

Самый популярный и эффективный алгоритм. Он использует принцип «разделяй и властвуй». Представьте, что вам нужно отсортировать стопку экзаменационных работ по баллам. Вы берёте одну работу (опорный элемент), и все, у кого балл меньше, кладёте в одну стопку слева, а все, у кого больше — в другую стопку справа. Потом вы повторяете то же самое с каждой из двух стопок. И так до тех пор, пока в каждой стопке не останется по одной работе.

Как это работает (упрощённо):

  1. Выбираем опорный элемент (pivot). Обычно берут средний или первый элемент.
  2. Переставляем элементы так, чтобы все, кто меньше опорного, оказались слева от него, а все, кто больше — справа. Сам опорный элемент оказывается на своём «законном» месте.
  3. Рекурсивно (то есть вызывая саму себя) применяем те же шаги к левой и правой частям массива.

Этот алгоритм работает в разы быстрее предыдущих, особенно на больших объёмах данных.

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

Синтаксис в PHP: все формы и варианты

PHP предоставляет богатый набор встроенных функций для сортировки массивов. Они делятся на две большие группы: сортировка по значениям и сортировка по ключам. Давайте разберём их все.

Сортировка по значениям (самое частое)

Функция Что делает Сохраняет ключи? Порядок
sort($array) Сортирует массив по возрастанию значений Нет (сбрасывает ключи) По возрастанию (1, 2, 3...)
rsort($array) Сортирует массив по убыванию значений Нет (сбрасывает ключи) По убыванию (9, 8, 7...)
asort($array) Сортирует массив по возрастанию значений Да (сохраняет) По возрастанию
arsort($array) Сортирует массив по убыванию значений Да (сохраняет) По убыванию

Сортировка по ключам (для ассоциативных массивов)

Функция Что делает Порядок
ksort($array) Сортирует массив по ключам по возрастанию По возрастанию (a, b, c...)
krsort($array) Сортирует массив по ключам по убыванию По убыванию (z, y, x...)

Пользовательская сортировка (для сложных случаев)

Если вам нужно отсортировать массив по какому-то нестандартному правилу (например, по длине строки, по последней букве, по вложенному полю объекта), используйте:

  • usort($array, 'callback_function') — сортирует значения, не сохраняя ключи.
  • uasort($array, 'callback_function') — то же самое, но сохраняет ключи.
  • uksort($array, 'callback_function') — сортирует ключи с помощью пользовательской функции.
Важно: Все эти функции изменяют исходный массив (работают по ссылке). Они не возвращают новый массив, а меняют старый. Если нужно сохранить оригинал, сначала скопируйте его: $copy = $original; sort($copy);

Примеры кода — от простого к сложному

Давайте перейдём к практике. Все примеры рабочие, вы можете скопировать их и запустить на своём компьютере.

Пример 1: Простейшая сортировка чисел

<?php
// Создаём массив с числами в беспорядке
$numbers = [5, 3, 8, 1, 9, 2, 7, 4, 6];

// Выводим исходный массив
echo "Исходный массив: ";
print_r($numbers);

// Используем встроенную функцию sort()
sort($numbers);

// Выводим отсортированный массив
echo "Отсортированный массив (по возрастанию): ";
print_r($numbers);
// Результат: [1, 2, 3, 4, 5, 6, 7, 8, 9]
?>

Объяснение: Мы создали массив чисел. Функция sort() отсортировала его по возрастанию. Обратите внимание: ключи массива были сброшены (теперь это 0, 1, 2...).

Пример 2: Сортировка строк (алфавитный порядок)

<?php
// Массив с именами
$names = ["Иван", "Анна", "Петр", "Мария", "Сергей"];

echo "Исходный массив: ";
print_r($names);

// Сортируем по алфавиту
sort($names);

echo "Отсортированный массив: ";
print_r($names);
// Результат: ["Анна", "Иван", "Мария", "Петр", "Сергей"]
?>

Объяснение: sort() отлично работает и со строками. Сортировка происходит по алфавиту (с учётом кодировки UTF-8).

Пример 3: Сортировка с сохранением ключей (asort)

<?php
// Ассоциативный массив: студент -> оценка
$grades = [
    "Иван" => 85,
    "Анна" => 92,
    "Петр" => 78,
    "Мария" => 95
];

echo "Исходный массив: ";
print_r($grades);

// Сортируем по оценкам (значениям), но сохраняем имена (ключи)
asort($grades);

echo "Отсортированный массив (по возрастанию оценок): ";
print_r($grades);
// Результат: ["Петр" => 78, "Иван" => 85, "Анна" => 92, "Мария" => 95]
// Ключи (имена) остались на своих местах!
?>

Объяснение: Если бы мы использовали sort(), то потеряли бы связь «имя → оценка». asort() сохраняет эту связь.

Пример 4: Сортировка по убыванию (rsort и arsort)

<?php
$scores = [10, 50, 30, 80, 20];

// Сортируем по убыванию (от лучшего к худшему)
rsort($scores);

echo "Результаты от лучшего к худшему: ";
print_r($scores);
// Результат: [80, 50, 30, 20, 10]

// Для ассоциативного массива используем arsort
$playerScores = ["Игрок1" => 150, "Игрок2" => 200, "Игрок3" => 120];
arsort($playerScores);
echo "Таблица лидеров: ";
print_r($playerScores);
// Результат: ["Игрок2" => 200, "Игрок1" => 150, "Игрок3" => 120]
?>

Объяснение: rsort() — обратная сортировка. Полезно для таблиц рекордов, где лучший результат должен быть первым.

Пример 5: Сортировка по ключам (ksort)

<?php
// Массив с кодами стран и их названиями
$countries = [
    "RU" => "Россия",
    "US" => "США",
    "DE" => "Германия",
    "FR" => "Франция"
];

echo "Исходный массив: ";
print_r($countries);

// Сортируем по кодам стран (ключам)
ksort($countries);

echo "Отсортированный массив (по кодам): ";
print_r($countries);
// Результат: ["DE" => "Германия", "FR" => "Франция", "RU" => "Россия", "US" => "США"]
?>

Объяснение: ksort() сортирует массив по ключам. Незаменимо, когда ключи имеют значение (например, ID товаров, коды стран).

Пример 6: Пользовательская сортировка (usort) — сортировка по длине строки

<?php
$words = ["яблоко", "дом", "компьютер", "кот", "программирование"];

echo "Исходный массив: ";
print_r($words);

// Сортируем по длине слова (от самого короткого к самому длинному)
usort($words, function($a, $b) {
    // Функция сравнения: возвращает отрицательное число, если a < b, положительное, если a > b, и 0, если равны
    return strlen($a) - strlen($b);
});

echo "Отсортированный массив (по длине): ";
print_r($words);
// Результат: ["дом", "кот", "яблоко", "компьютер", "программирование"]
?>

Объяснение: usort() принимает функцию, которая сравнивает два элемента. Мы используем анонимную функцию (лямбду), которая сравнивает длины строк. strlen() возвращает длину строки.

Пример 7: Сортировка многомерного массива (по вложенному полю)

<?php
// Массив с товарами (каждый товар — это массив)
$products = [
    ["name" => "Ноутбук", "price" => 50000],
    ["name" => "Мышь", "price" => 1500],
    ["name" => "Клавиатура", "price" => 3000],
    ["name" => "Монитор", "price" => 25000]
];

echo "Исходный массив: ";
print_r($products);

// Сортируем по цене (от дешёвых к дорогим)
usort($products, function($a, $b) {
    return $a['price'] - $b['price'];
});

echo "Отсортированный массив (по цене): ";
print_r($products);
// Результат: Мышь (1500), Клавиатура (3000), Монитор (25000), Ноутбук (50000)
?>

Объяснение: Это самый частый случай в реальной работе. У нас есть массив массивов. Мы используем usort() и внутри функции сравнения обращаемся к полю price каждого элемента.

Пример 8: Сортировка в обратном порядке с пользовательской функцией

<?php
$students = [
    ["name" => "Иван", "age" => 20],
    ["name" => "Анна", "age" => 19],
    ["name" => "Петр", "age" => 22]
];

// Сортируем по возрасту от старшего к младшему
usort($students, function($a, $b) {
    // Меняем местами a и b для обратного порядка
    return $b['age'] - $a['age'];
});

echo "Студенты от старшего к младшему: ";
print_r($students);
// Результат: Петр (22), Иван (20), Анна (19)
?>

Объяснение: Чтобы изменить порядок сортировки на противоположный, достаточно поменять местами $a и $b в выражении сравнения.

Сравнение с Python: чем похоже и чем отличается

Если вы уже знакомы с Python или планируете его изучать, вот ключевые различия в подходах к сортировке:

Характеристика PHP Python
Основная функция sort($array) — изменяет исходный массив sorted($list) — возвращает новый отсортированный список, исходный не меняется
Метод объекта Нет метода, только функции $list.sort() — изменяет исходный список (аналог PHP sort())
Сохранение ключей Есть отдельные функции: asort(), ksort() Словари (аналог ассоциативных массивов) нельзя сортировать напрямую. Нужно использовать sorted(dict.items())
Пользовательская сортировка usort($array, 'func') или анонимная функция sorted($list, key=lambda x: ...) — более элегантный синтаксис
Сортировка по убыванию rsort(), arsort() sorted($list, reverse=True)
Стабильность Не гарантируется (зависит от версии PHP) Гарантируется (элементы с равными ключами сохраняют порядок)

Главное отличие: В Python сортировка чаще всего не изменяет исходные данные, а возвращает новые. В PHP сортировка всегда изменяет исходный массив. Это важно помнить, чтобы случайно не потерять данные.

Совет: Если вы привыкли к Python и хотите «безопасного» поведения в PHP (не менять исходный массив), просто копируйте его перед сортировкой: $sorted = $original; sort($sorted);

Типичные ошибки и подводные камни

Даже опытные программисты иногда попадаются на этих граблях. Вот список самых частых ошибок:

Ошибка 1: Забыли, что sort() изменяет исходный массив

<?php
$data = [3, 1, 2];
$sorted = sort($data); // ОШИБКА! sort() возвращает true/false, а не массив!
// $sorted теперь true, а $data изменился
print_r($sorted); // Выведет: 1 (true)
print_r($data);   // Выведет: [1, 2, 3]
?>

Как правильно: sort($data); — просто вызовите функцию, и массив $data изменится сам.

Ошибка 2: Сортировка ассоциативного массива с sort()

<?php
$user = ["name" => "Иван", "age" => 25, "city" => "Москва"];
sort($user); // Все ключи будут потеряны!
print_r($user); // Выведет: [0 => "Иван", 1 => 25, 2 => "Москва"]
?>

Как правильно: Используйте asort() (сортировка по значениям с сохранением ключей) или ksort() (сортировка по ключам).

Ошибка 3: Сравнение строк с разной кодировкой

<?php
$words = ["ёлка", "елка", "яблоко"];
sort($words); // Результат может быть неожиданным из-за кодировки
print_r($words); // Может вывести: ["елка", "яблоко", "ёлка"] (ё в конце)
?>

Как правильно: Используйте setlocale(LC_ALL, 'ru_RU.utf8'); перед сортировкой или функцию strcoll() для сравнения строк с учётом локали.

Ошибка 4: Сортировка объектов без метода сравнения

<?php
class Product {
    public $price;
    public function __construct($price) {
        $this->price = $price;
    }
}

$products = [new Product(100), new Product(50), new Product(200)];
sort($products); // ОШИБКА! PHP не знает, как сравнивать объекты
?>

Как правильно: Используйте usort() и сравнивайте конкретные свойства объектов.

Ошибка 5: Предположение, что сортировка стабильна

В PHP (до версии 8.0) сортировка не была стабильной. Это значит, что если два элемента равны, их порядок мог измениться. В PHP 8.0+ все функции сортировки стали стабильными, но на старых версиях это может привести к багам.

Лучшие практики и советы профессионалов

Вот несколько правил, которые помогут вам писать правильный и эффективный код:

  1. Всегда используйте встроенные функции. Не пишите свою сортировку пузырьком. Встроенные функции написаны на C, они работают в десятки раз быстрее вашего PHP-кода.
  2. Выбирайте правильную функцию. Если вам не важны ключи — используйте sort(). Если важны — asort(). Если нужно сортировать по ключам — ksort().
  3. Для сложной сортировки используйте usort() с анонимными функциями. Это гибко и читаемо.
  4. Не бойтесь копировать массивы. Если вам нужно сохранить исходный порядок, просто сделайте $copy = $array; перед сортировкой.
  5. Используйте array_multisort() для сортировки нескольких массивов одновременно. Например, если у вас есть массив имён и массив возрастов, и вы хотите отсортировать их вместе.
  6. Помните о производительности. Для массивов до 100 элементов разница между алгоритмами незаметна. Для массивов от 1000 элементов используйте только быструю сортировку (встроенные функции).
  7. Тестируйте на граничных случаях. Пустой массив, массив с одним элементом, массив со всеми одинаковыми элементами — ваша сортировка должна работать корректно во всех случаях.
Золотое правило: «Преждевременная оптимизация — корень всех зол». Сначала напишите понятный и работающий код. Если он работает медленно — профилируйте и оптимизируйте только узкие места. В 99% случаев встроенной сортировки PHP более чем достаточно.

Вопросы для самопроверки

Проверьте, как вы усвоили материал. Постарайтесь ответить на вопросы, не подглядывая в ответы.

  1. Вопрос: Какая функция PHP сортирует массив по возрастанию, но НЕ сохраняет ключи?
    Ответ: sort()
  2. Вопрос: Чем отличается sort() от asort()?
    Ответ: sort() сбрасывает ключи и присваивает новые числовые индексы. asort() сохраняет связь между ключом и значением.
  3. Вопрос: Как отсортировать массив по убыванию значений, сохраняя ключи?
    Ответ: Использовать функцию arsort().
  4. Вопрос: Какая функция используется для сортировки массива по ключам?
    Ответ: ksort() (по возрастанию) и krsort() (по убыванию).
  5. Вопрос: Что вернёт функция sort()?
    Ответ: true в случае успеха и false в случае ошибки. Сам массив изменяется по ссылке.
  6. Вопрос: Как отсортировать массив объектов по свойству price?
    Ответ: Использовать usort($array, function($a, $b) { return $a->price <=> $b->price; }); (используя космический оператор <=>).
  7. Вопрос: Что такое «стабильная сортировка»?
    Ответ: Это сортировка, которая сохраняет относительный порядок равных элементов. В PHP 8.0+ все сортировки стабильны.
  8. Вопрос: Какая функция позволяет отсортировать массив по пользовательскому правилу, сохраняя ключи?
    Ответ: uasort().
  9. Вопрос: Что произойдёт, если применить sort() к ассоциативному массиву?
    Ответ: Массив будет отсортирован по значениям, но все строковые ключи будут потеряны и заменены числовыми индексами.
  10. Вопрос: Какой алгоритм сортировки используется во встроенных функциях PHP?
    Ответ: В PHP используется реализация быстрой сортировки (Quicksort) с некоторыми оптимизациями.

Итог и что изучить дальше

Мы проделали огромный путь! Вы узнали:

  • Что такое сортировка и зачем она нужна (аналогия с библиотекой).
  • Как работают основные алгоритмы: пузырьковая сортировка, сортировка выбором и быстрая сортировка.
  • Полный арсенал встроенных функций PHP для сортировки: sort(), rsort(), asort(), arsort(), ksort(), krsort(), usort(), uasort(), uksort().
  • Как применять их на практике с 8 подробными примерами.
  • Чем PHP отличается от