Queue
This page introduces data structures related to queues and their applications.
Introduction
A queue is a type of list with the property that "elements that enter the queue first will definitely leave the queue first." Due to this property, a queue is often referred to as a First-In-First-Out (FIFO) list.
Implementation
Array Simulation of a Queue
Typically, an array is used to simulate a queue, with two variables marking the head and tail of the queue.
1 | |
The corresponding code for queue operations is as follows:
- Insert element:
q[++qr] = x; - Delete element:
ql++; - Access front element:
q[ql] - Access rear element:
q[qr] - Clear queue:
ql = 1; qr = 0;
Luogu B3616【Template】Queue Array Simulation Reference Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
Double Stack Simulation of a Queue
Another less common method is to use two stacks to simulate a queue.
This method uses two stacks \(F\) and \(S\) to simulate a queue, where \(F\) is the stack at the rear of the queue, and \(S\) represents the stack at the front of the queue. It supports push (insert at the rear) and pop (remove from the front) operations:
- push: Insert into stack \(F\).
- pop: If \(S\) is not empty, pop from \(S\); otherwise, transfer all elements from \(F\) to \(S\) (by popping from \(F\) and pushing into \(S\), which reverses their order), then pop from \(S\).
It can be easily proven that each element is only pushed/transferred/popped once, resulting in an amortized complexity of \(O(1)\).
Luogu B3616【Template】Queue Double Stack Simulation Reference Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | |
Queue in C++ STL
C++ provides a container std::queue in the STL. To use it, include the <queue> header.
STL Definition of queue
1 2 3 4 5 | |
T is the data type stored in the queue.
Container is the underlying container type used to store elements. This container must provide the following functions with their usual semantics:
back()front()push_back()pop_front()
The STL containers std::deque and std::list satisfy these requirements. If not specified, std::deque is used as the default underlying container.
The queue container in STL provides a set of member functions for use. Commonly used ones include:
- Element Access
q.front()returns the front elementq.back()returns the rear element
- Modification
q.push()inserts an element at the rearq.pop()removes the front element
- Capacity
q.empty()checks if the queue is emptyq.size()returns the number of elements in the queue
Additionally, queue provides some operators. The most commonly used is the assignment operator = to assign one queue to another. Example:
1 2 3 4 5 6 7 8 9 10 11 | |
Special Queues
Double-ended Queue
A double-ended queue (deque) is a queue that allows insertion and deletion at both the front and the rear. It essentially combines the functionalities of a stack and a queue. Specifically, a deque supports four operations:
- Insert an element at the front
- Insert an element at the rear
- Delete an element from the front
- Delete an element from the rear
The method for simulating a deque with an array is the same as for a regular queue.
Similarly, the idea of using two stacks to simulate a queue can be adapted to maintain a deque. However, note that if one stack becomes empty, alternating queries to the front and rear may break the amortized analysis. To address this, when moving elements, only half of the elements from the non-empty stack are moved to the empty stack, while preserving the properties of the front and rear stacks. This approach still achieves amortized constant-time insertion and deletion.
Brief Proof
Since insertion operations contribute only constant complexity, consider the deletion operations. Suppose the queue initially has \(m\) elements. We calculate the time complexity to pop all elements (from either end). The first balancing operation costs \(O(m)\). Then each stack has \(\frac{m}{2}\) elements. Clearing one stack then costs \(O(\frac{m}{2})\), which can trigger another balancing operation of complexity \(O(\frac{m}{2})\), and so on, until all elements are popped. Therefore, the total complexity is
By the Master Theorem, \(T(m)=O(m)\). Thus, the total complexity of this maintenance method remains amortized constant.
Luogu B3656【Template】Double-ended Queue 1 Reference Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
Double-ended Queue in C++ STL
C++ also provides a container std::deque in the STL. To use it, include the <deque> header.
STL Definition of deque
1 2 3 4 5 | |
T is the data type stored in the deque.
Allocator is the allocator. This is not discussed in detail here; generally, the default is sufficient.
The deque container in STL provides a set of member functions for use. Commonly used ones include:
- Element Access
q.front()returns the front elementq.back()returns the rear element
- Modification
q.push_back()inserts an element at the rearq.pop_back()removes the rear elementq.push_front()inserts an element at the frontq.pop_front()removes the front elementq.insert()inserts an element before a specified position (takes an iterator and an element)q.erase()deletes an element at a specified position (takes an iterator)
- Capacity
q.empty()checks if the deque is emptyq.size()returns the number of elements in the deque
Additionally, deque provides some operators. Commonly used ones include:
- Using the assignment operator
=to assign one deque to another, similar toqueue. - Using
[]to access elements, similar tovector.
The <queue> header also provides the priority queue std::priority_queue, which is more similar to a heap and is not discussed in detail here.
Double-ended Queue in Python
In Python, the deque container is provided by collections.deque.
Example:
Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Circular Queue
Using an array to simulate a queue leads to an issue: over time, the entire queue shifts toward the end of the array. Once it reaches the end of the array, even if there is free space at the front of the array, further enqueue operations will cause overflow (this phenomenon, where overflow occurs despite available space in the array, is called "false overflow").
The solution to false overflow is to organize the array storing the queue elements in a circular manner. That is, treat position 0 of the array as the successor of the last position. (For an element at index x, its successor is (x + 1) % SIZE). This forms a circular queue.
References
本页面最近更新:,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:OI-wiki
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用