что такое очередь
Очередь — это еще одна линейная структура данных, которая следует принципу FIFO. Есть два конца очереди для работы, один конец удаляется из очереди, а другой конец ставится в очередь. Эта особенность отличается от стека, который имеет только один конец, который можно использовать для операций. Постановка в очередь всегда в конце, а удаление из очереди всегда впереди.
Общие операции
- поставить в очередь -> поставить в очередь
- исключить из очереди -> исключить из очереди
- peek -> возвращает передний элемент очереди
- isEmpty -> пусто
PHP-реализация
Сначала мы определяем QueueInterface.
interface QueueInterface
{
public function enqueue(string $item);
public function dequeue();
public function isEmpty();
public function peek();
}
Давайте посмотрим на реализацию очереди на основе массива.
class ArrQueue implements QueueInterface
{
private $queue;
private $limit;
public function __construct(int $limit = 0)
{
$this->limit = $limit;
$this->queue = [];
}
public function isEmpty()
{
return empty($this->queue);
}
public function dequeue()
{
if ($this->isEmpty()) {
throw new \UnderflowException('queue is empty');
} else {
array_shift($this->queue);
}
}
public function enqueue(string $item)
{
if (count($this->queue) >= $this->limit) {
throw new \OverflowException('queue is full');
} else {
array_unshift($this->queue, $item);
}
}
public function peek()
{
return current($this->queue);
}
}
Благодаря мощной структуре массивов PHP мы можем легко написать основной метод работы с очередью. Конечно же, лучший в мире язык оправдывает свою репутацию.
Возможно, остроумные одноклассники догадались, что я уже определил интерфейс очереди, и реализация очереди должна быть больше, чем приведенная выше. Давайте посмотрим на реализацию на основе связанного списка.
class LinkedListQueue implements QueueInterface
{
private $limit;
private $queue;
public function __construct(int $limit = 0)
{
$this->limit = $limit;
$this->queue = new LinkedList();
}
public function isEmpty()
{
return $this->queue->getSize() == 0;
}
public function peek()
{
return $this->queue->getNthNode(0)->data;
}
public function enqueue(string $item)
{
if ($this->queue->getSize() < $this->limit) {
$this->queue->insert($item);
} else {
throw new \OverflowException('queue is full');
}
}
public function dequeue()
{
if ($this->isEmpty()) {
throw new \UnderflowException('queue is empty');
} else {
$lastItem = $this->peek();
$this->queue->deleteFirst();
return $lastItem;
}
}
}
Он включает в себя предыдущую реализацию связанного списка, студенты, которые не знают деталей, могут перейти кздесьпосмотри.
Очередь в Спл
Мощный PHP имеет встроенную реализацию очереди, и методы, которые можно использовать, аналогичны тем, которые мы реализовали сами выше.
class SqlQueue
{
private $splQueue;
public function __construct()
{
$this->splQueue = new \SplQueue();
}
public function enqueue(string $data = null)
{
$this->splQueue->enqueue($data);
}
public function dequeue()
{
return $this->splQueue->dequeue();
}
}
приоритетная очередь
Очередь с приоритетом — это особый вид очереди, и порядок постановки в очередь или исключения из очереди зависит от веса каждого узла.
последовательная последовательность
Очереди с приоритетом можно разделить на очереди с упорядоченным приоритетом и очереди с неупорядоченным приоритетом. Существует два типа очередей с упорядоченным приоритетом: обратный порядок или последовательный порядок. В последовательной последовательности мы можем быстро найти узел с наибольшим или наименьшим приоритетом, а сложность — O(1). Но его вставка займет больше времени, потому что мы должны проверить приоритет каждого узла и вставить его в соответствующую позицию.
неупорядоченная последовательность
В неупорядоченной последовательности при вставке новых узлов нам не нужно определять позицию по их приоритету. При входе в очередь он вставляется в конец очереди, как обычная очередь. Но когда мы хотим удалить элемент с наивысшим приоритетом, мы должны сканировать каждый узел, чтобы определить, какой из них имеет наивысший приоритет для удаления. Далее мы реализуем очередь с последовательным приоритетом на основе связанного списка.
class LinkedListPriorityQueue
{
private $limit;
private $queue;
public function __construct(int $limit = 0)
{
$this->limit = $limit;
$this->queue = new LinkedList();
}
public function enqueue(string $data = null, int $priority)
{
if ($this->queue->getSize() > $this->limit) {
throw new \OverflowException('Queue is full');
} else {
$this->queue->insert($data, $priority);
}
}
public function dequeue(): string
{
if ($this->isEmpty()) {
throw new \UnderflowException('Queue is empty');
} else {
$item = $this->peek();
$this->queue->deleteFirst();
return $item->data;
}
}
public function peek()
{
return $this->queue->getNthNode(0);
}
public function isEmpty()
{
return $this->queue->getSize() === 0;
}
}
круговая очередь
Чтобы в полной мере использовать векторное пространство, метод преодоления явления «ложного переполнения» состоит в том, чтобы представить векторное пространство как сквозное кольцо и назвать этот вектор круговым вектором. Хранящаяся в нем очередь называется циклической очередью. Циклическая очередь тоже является массивом, но логически соединяет голову и хвост массива, образуя циклическую очередь.Когда хвост массива заполнен, необходимо оценить, пуста ли голова массива, и продолжить для хранения данных, если он не пуст.
class CircularQueue implements QueueInterface
{
private $queue;
private $limit;
private $front = 0;
private $rear = 0;
public function __construct(int $limit = 0)
{
$this->limit = $limit;
$this->queue = [];
}
public function isEmpty()
{
return $this->front === $this->rear;
}
public function isFull()
{
$diff = $this->rear - $this->front;
if ($diff == -1 || $diff == ($this->limit - 1)) {
return true;
}
return false;
}
public function peek()
{
return $this->queue[$this->front];
}
public function dequeue()
{
if ($this->isEmpty()) {
throw new \UnderflowException('Queue is empty');
}
$item = $this->queue[$this->front];
$this->queue[$this->front] = null;
$this->front = ($this->front + 1) % $this->limit;
return $item;
}
public function enqueue(string $item)
{
if ($this->isFull()) {
throw new \OverflowException('Queue is full');
}
$this->queue[$this->rear] = $item;
$this->rear = ($this->rear + 1) % $this->limit;
}
}
дека
Все очереди, которые мы реализовали до сих пор, помещаются в конец очереди и выходят из нее в начале очереди. В особых случаях мы надеемся, что как голова, так и хвост команды могут войти в очередь или выйти из нее.Такая структура называется двусторонней очередью. Основываясь на структуре связанного списка, которую мы реализовали ранее, мы можем легко реализовать такую структуру.
class LinkedListDeQueue
{
private $limit = 0;
private $queue;
public function __construct(int $limit = 0)
{
$this->limit = $limit;
$this->queue = new \DataStructure\LinkedList\LinkedList();
}
public function dequeueFromFront(): string
{
if ($this->isEmpty()) {
throw new \UnderflowException('Queue is empty');
}
$item = $this->queue->getNthNode(0);
$this->queue->deleteFirst();
return $item->data;
}
public function dequeueFromBack(): string
{
if ($this->isEmpty()) {
throw new \UnderflowException('Queue is empty');
}
$item = $this->queue->getNthNode($this->queue->getSize() - 1);
$this->queue->deleteLast();
return $item->data;
}
public function isFull()
{
return $this->queue->getSize() >= $this->limit;
}
public function enqueueAtBack(string $data = null)
{
if ($this->isFull()) {
throw new \OverflowException('queue is full');
}
$this->queue->insert($data);
}
public function enqueueAtFront(string $data = null)
{
if ($this->isFull()) {
throw new \OverflowException('queue is full');
}
$this->queue->insertAtFirst($data);
}
public function isEmpty()
{
return $this->queue->getSize() === 0;
}
public function peekFront()
{
return $this->queue->getNthNode(0)->data;
}
public function peekBack()
{
return $this->queue->getNthNode($this->queue->getSize() - 1)->data;
}
}
Он включает в себя предыдущую реализацию связанного списка, студенты, которые не знают деталей, могут перейти кздесьпосмотри.
Суммировать
Стеки и очереди — наши наиболее часто используемые структуры данных, и мы увидим применение этих двух абстрактных типов данных в других сложных структурах данных. В следующей главе мы перейдем к рекурсии структур данных PHP — распространенному способу упрощения сложных задач.
Тематическая серия
Адрес каталога серии тем по базовой структуре данных PHP:github.com/...Он в основном использует синтаксис PHP для обобщения основных структур данных и алгоритмов. Есть также базовые знания, которые легко игнорировать в нашей повседневной разработке PHP, и некоторые практические предложения по спецификации, развертыванию и оптимизации в современной разработке PHP, а также углубленное исследование характеристик языка Javascript.