Алгоритмы и структуры данных на PHP: от теории к рабочим проектам
Многие PHP-разработчики считают, что алгоритмы и структуры данных — это удел C++ или Java. Однако на практике понимание базовых алгоритмов напрямую влияет на производительность и масштабируемость веб-приложений. В этой статье мы разберём ключевые структуры данных и алгоритмы на PHP с реальными примерами кода, которые можно сразу применить в своих проектах.
Зачем PHP-разработчику знать алгоритмы?
PHP традиционно ассоциируется с быстрой разработкой веб-сайтов, но современные фреймворки (Laravel, Symfony) и высоконагруженные проекты требуют эффективного управления данными. Без понимания алгоритмов вы рискуете:
- Писать медленные запросы к БД, которые можно заменить кешированием через хеш-таблицы;
- Создавать неоптимальные циклы с вложенностью O(n³);
- Терять контроль над памятью при обработке больших массивов.
Базовые структуры данных — это фундамент, на котором строятся все современные системы. Рассмотрим их реализацию на PHP.
Структуры данных на PHP: реализация и примеры
1. Стек (Stack) — принцип LIFO
Стек работает по принципу «последний пришёл — первый ушёл». В PHP его легко реализовать через массив с функциями array_push() и array_pop(). Однако для учебных целей и лучшего понимания создадим класс:
<?php
class Stack {
private array $items = [];
public function push($item): void {
$this->items[] = $item;
}
public function pop() {
if ($this->isEmpty()) {
return null;
}
return array_pop($this->items);
}
public function peek() {
return $this->items[count($this->items) - 1] ?? null;
}
public function isEmpty(): bool {
return empty($this->items);
}
}
// Пример использования
$stack = new Stack();
$stack->push('Пользователь 1');
$stack->push('Пользователь 2');
echo $stack->pop(); // Пользователь 2
?>
Где применяется: проверка корректности скобок в коде, отмена действий (undo), обход графов в глубину.
2. Очередь (Queue) — принцип FIFO
Очередь работает как живая очередь: первый вошёл — первый вышел. Используем array_shift() и array_push():
<?php
class Queue {
private array $items = [];
public function enqueue($item): void {
$this->items[] = $item;
}
public function dequeue() {
if ($this->isEmpty()) {
return null;
}
return array_shift($this->items);
}
public function isEmpty(): bool {
return empty($this->items);
}
}
// Пример: обработка задач в фоне
$queue = new Queue();
$queue->enqueue('Отправить email');
$queue->enqueue('Сгенерировать отчёт');
echo $queue->dequeue(); // Отправить email
?>
Где применяется: очереди задач (Job Queue), обработка запросов в порядке поступления, обход графов в ширину (BFS).
3. Хеш-таблица (Hash Table) — быстрый поиск
В PHP ассоциативные массивы — это встроенная хеш-таблица. Но для понимания внутренней механики реализуем простую версию с коллизиями через цепочки:
<?php
class HashTable {
private array $buckets;
private int $size;
public function __construct(int $size = 10) {
$this->size = $size;
$this->buckets = array_fill(0, $size, []);
}
private function hash(string $key): int {
return crc32($key) % $this->size;
}
public function set(string $key, $value): void {
$index = $this->hash($key);
foreach ($this->buckets[$index] as &$item) {
if ($item[0] === $key) {
$item[1] = $value;
return;
}
}
$this->buckets[$index][] = [$key, $value];
}
public function get(string $key) {
$index = $this->hash($key);
foreach ($this->buckets[$index] as $item) {
if ($item[0] === $key) {
return $item[1];
}
}
return null;
}
}
// Пример: кеширование данных
$cache = new HashTable();
$cache->set('user:123', ['name' => 'Анна', 'role' => 'admin']);
print_r($cache->get('user:123'));
?>
Где применяется: кеширование (Redis, Memcached), хранение сессий, индексация данных.
Алгоритмы на PHP: от простого к сложному
1. Линейный и бинарный поиск
Линейный поиск — самый простой, но медленный (O(n)). Бинарный поиск работает только на отсортированных данных, но даёт O(log n):
<?php
function binarySearch(array $arr, int $target): int {
$left = 0;
$right = count($arr) - 1;
while ($left <= $right) {
$mid = intdiv($left + $right, 2);
if ($arr[$mid] === $target) {
return $mid;
}
if ($arr[$mid] < $target) {
$left = $mid + 1;
} else {
$right = $mid - 1;
}
}
return -1;
}
$sorted = [1, 3, 5, 7, 9, 11];
echo binarySearch($sorted, 7); // 3
?>
Совет: Всегда используйте бинарный поиск для поиска в отсортированных массивах — это даёт прирост скорости в десятки раз на больших объёмах данных.
2. Сортировка пузырьком и быстрая сортировка
Пузырьковая сортировка — учебный пример (O(n²)). На практике используйте встроенную sort() или реализуйте быструю сортировку (QuickSort):
<