This commit is contained in:
krahets
2026-04-03 18:46:15 +08:00
parent 377736b1bd
commit 9d21ca86b0
352 changed files with 46563 additions and 11262 deletions
+16 -16
View File
@@ -6,7 +6,7 @@ comments: true
<u>Очередь (queue)</u> - это линейная структура данных, подчиняющаяся правилу "первым пришел - первым вышел". Как видно из названия, очередь моделирует обычную ситуацию ожидания: новые люди непрерывно присоединяются к хвосту очереди, а стоящие в начале по одному уходят.
Как показано на рисунке 5-4, начало очереди называется "головой очереди", а конец - "хвостом очереди"; операцию добавления элемента в хвост называют "enqueue", а операцию удаления элемента из головы - "dequeue".
Как показано на рисунке 5-4, начало очереди называется головой очереди, а конец - хвостом очереди; операцию добавления элемента в хвост называют `enqueue`, а операцию удаления элемента из головы - `dequeue`.
![Правило FIFO для очереди](queue.assets/queue_operations.png){ class="animation-figure" }
@@ -28,7 +28,7 @@ comments: true
</div>
Мы можем напрямую использовать готовые классы очереди, предоставляемые языками программирования:
Обычно достаточно использовать готовые классы очереди, предоставляемые языками программирования:
=== "Python"
@@ -376,15 +376,15 @@ comments: true
### 1. &nbsp; Реализация на основе связного списка
Как показано на рисунке 5-5, мы можем рассматривать "головной узел" и "хвостовой узел" связного списка как "голову очереди" и "хвост очереди" соответственно, договорившись, что добавлять узлы можно только в хвост, а удалять - только из головы.
Как показано на рисунке 5-5, мы можем рассматривать головной узел и хвостовой узел связного списка как голову очереди и хвост очереди соответственно, договорившись, что добавлять узлы можно только в хвост, а удалять - только из головы.
=== "LinkedListQueue"
=== "<1>"
![Операции enqueue и dequeue в реализации очереди на связном списке](queue.assets/linkedlist_queue_step1.png){ class="animation-figure" }
=== "push()"
=== "<2>"
![linkedlist_queue_push](queue.assets/linkedlist_queue_step2_push.png){ class="animation-figure" }
=== "pop()"
=== "<3>"
![linkedlist_queue_pop](queue.assets/linkedlist_queue_step3_pop.png){ class="animation-figure" }
<p align="center"> Рисунок 5-5 &nbsp; Операции enqueue и dequeue в реализации очереди на связном списке </p>
@@ -1317,29 +1317,29 @@ comments: true
### 2. &nbsp; Реализация на основе массива
Удаление первого элемента из массива имеет временную сложность $O(n)$ , из-за чего операция dequeue оказывается неэффективной. Однако этого можно избежать с помощью следующего приема.
Удаление первого элемента из массива имеет временную сложность $O(n)$ , из-за чего операция `dequeue` оказывается неэффективной. Однако этого можно избежать с помощью следующего приема.
Мы можем использовать переменную `front` , указывающую на индекс элемента в голове очереди, и поддерживать переменную `size` , которая хранит длину очереди. Определим `rear = front + size` ; эта формула дает позицию `rear`, указывающую на ячейку сразу после хвоста очереди.
Исходя из этого, **эффективный диапазон элементов массива равен `[front, rear - 1]`**, а различные операции реализуются, как показано на рисунке 5-6.
- Операция enqueue: записать входной элемент по индексу `rear` и увеличить `size` на 1.
- Операция dequeue: просто увеличить `front` на 1 и уменьшить `size` на 1.
- Операция `enqueue`: записать входной элемент по индексу `rear` и увеличить `size` на 1.
- Операция `dequeue`: просто увеличить `front` на 1 и уменьшить `size` на 1.
Можно увидеть, что и enqueue, и dequeue требуют всего одной операции, а значит обе имеют временную сложность $O(1)$ .
Можно увидеть, что и `enqueue` , и `dequeue` требуют всего одной операции, а значит обе имеют временную сложность $O(1)$ .
=== "ArrayQueue"
=== "<1>"
![Операции enqueue и dequeue в реализации очереди на массиве](queue.assets/array_queue_step1.png){ class="animation-figure" }
=== "push()"
=== "<2>"
![array_queue_push](queue.assets/array_queue_step2_push.png){ class="animation-figure" }
=== "pop()"
=== "<3>"
![array_queue_pop](queue.assets/array_queue_step3_pop.png){ class="animation-figure" }
<p align="center"> Рисунок 5-6 &nbsp; Операции enqueue и dequeue в реализации очереди на массиве </p>
Ты можешь заметить еще одну проблему: при непрерывных операциях enqueue и dequeue значения `front` и `rear` оба движутся вправо, и **когда они доходят до конца массива, дальше сдвигаться уже нельзя**. Чтобы решить эту проблему, можно рассматривать массив как "кольцевой массив", у которого начало и конец соединены.
Ты можешь заметить еще одну проблему: при непрерывных операциях `enqueue` и `dequeue` значения `front` и `rear` оба движутся вправо, и **когда они доходят до конца массива, дальше сдвигаться уже нельзя**. Чтобы решить эту проблему, можно рассматривать массив как кольцевой массив, у которого начало и конец соединены.
Для кольцевого массива нужно сделать так, чтобы `front` или `rear`, перешагнув конец массива, сразу возвращались к его началу и продолжали движение. Такую периодичность удобно реализовать с помощью операции взятия остатка, как показано в коде ниже:
@@ -2071,7 +2071,7 @@ comments: true
typedef struct {
int *nums; // Массив для хранения элементов очереди
int front; // Указатель head, указывающий на первый элемент очереди
int queSize; // Указатель хвоста, указывающий на позицию после хвоста
int queSize; // Текущее количество элементов в очереди
int queCapacity; // Вместимость очереди
} ArrayQueue;
@@ -2296,5 +2296,5 @@ comments: true
## 5.2.3 &nbsp; Типичные применения очереди
- **Заказы на Taobao**. После оформления заказа покупателем заказ попадает в очередь, а затем система обрабатывает заказы по порядку. Во время крупных распродаж, таких как Double 11, за короткое время возникает огромный поток заказов, и высокая конкурентная нагрузка становится ключевой инженерной проблемой.
- **Очереди заказов**. После оформления заказа покупателем заказ попадает в очередь, а затем система обрабатывает заказы по порядку. Во время крупных распродаж за короткое время возникает огромный поток заказов, и высокая конкурентная нагрузка становится ключевой инженерной проблемой.
- **Различные отложенные задачи**. Любой сценарий, где нужно реализовать принцип "кто раньше пришел, тот раньше обслуживается", например очередь заданий принтера или очередь блюд на кухне ресторана, хорошо моделируется очередью, которая эффективно поддерживает нужный порядок обработки.