In C++, we could implement an array-based queue as a class. To conserve space, we'll implement it as a "circular queue", an array in which the last position is logically connected back to the first position to make a circle. This is sometimes also called a "ring buffer".
Data members
q_array
- Queue array pointer. A pointer to the data type of the items stored in the queue; points to the first element of a dynamically-allocated array.q_capacity
- Queue capacity. The number of elements in the queue array.q_size
- Queue size. The number of items currently stored in the queue.q_front
- Queue front. The subscript of the front (or head) item in the queue.q_back
- Queue back. The subscript of the back (or rear or tail) item in the queue.Member Functions
The example functions described here correspond to the interface of the queue
class in the C++ standard library. Variations are certainly possible; for example, the push()
operation described here is frequently called "enqueue" while the pop()
operation is frequently called "dequeue".
Default constructor
Sets queue to initial empty state. The queue capacity and queue size should be set to 0. The queue array pointer should be set to nullptr
. q_front
should be set to 0, while q_back
is set to q_capacity - 1
.
size()
Returns the queue size.
empty()
Returns true if the queue size is 0; otherwise, false.
clear()
Sets the queue size back to 0 and resets q_front
and q_back
to their initial values. Does not deallocate any dynamic storage or change the queue capacity.
front()
Returns the front item of the queue (q_array[q_front]
).
back()
Returns the back item of the queue (q_array[q_back]
).
push()
Inserts a new item at the back of the queue.
procedure push(value: item to insert) // If queue is full, reserve additional storage. if q_size == q_capacity if q_capacity == 0 reserve(1) else reserve(q_capacity * 2) end if // Increment q_back, wrapping around to the beginning of the array if // necessary. q_back ← (q_back + 1) % q_capacity // Insert the item at the back of the queue and increment the queue size. q_array[q_back] ← value q_size ← q_size + 1 end procedure
pop()
Removes the front item from the queue.
procedure pop() // Increment q_front, wrapping around to the beginning of the array if // necessary. q_front ← (q_front + 1) % q_capacity q_size ← q_size - 1 end procedure
Copy constructor
Similar to the copy constructor for the example Vector
class in the notes on dynamic storage allocation. A key difference is that we cannot assume that the items in the queue are stored in elements 0 to q_size - 1
the way we can in the Vector
or an array-based stack. It is therefore necessary to copy the entire queue array.
Copy assignment operator
Similar to the copy assignment operator for the example Vector
class in the notes on dynamic storage allocation. A key difference is that we cannot assume that the items in the queue are stored in elements 0 to q_size - 1
the way we can in the Vector
or an array-based stack. It is therefore necessary to copy the entire queue array.
Destructor
Deletes the queue array.
reserve()
Reserves additional storage for the queue array. The process of copying the original array contents into the new, larger array is complicated by the fact that the exact locations of the queue items within the queue array are unknown and that there is no guarantee that q_front
is less than q_back
.
procedure reserve(n: amount of storage to reserve) if n < q_size or n == q_capacity return end if Allocate a new array of size n called temp_array // Copy the contents of q_array into temp_array i ← 0 j ← q_front while i < q_size temp_array[i] ← q_array[j] j ← (j + 1) % q_capacity i ← i + 1 end while q_capacity ← n Delete q_array q_array ← temp_array q_front ← 0 q_back ← q_size - 1 end procedure
We can also easily implement a double-ended queue using an array. The push()
operation becomes push_back()
while the pop()
operation becomes pop_front()
. No other changes to the code previously described are required. The following two operations can be added to insert an item at the front of the double-ended queue and to remove an item from the back of the double-ended queue.
push_front()
Inserts a new item at the front of the queue.
procedure push_front(value: item to insert) // If queue is full, reserve additional storage. if q_size == q_capacity if q_capacity == 0 reserve(1) else reserve(q_capacity * 2) end if // Decrement q_front, wrapping around to the end of the array if // necessary. q_front ← (((q_front - 1) % q_capacity) + q_capacity) % q_capacity // Insert the item at the front of the queue and increment the queue size. q_array[q_front] ← value q_size ← q_size + 1 end procedure
pop_back()
Removes the back item from the queue.
procedure pop_back() // Decrement q_back, wrapping around to the end of the array if // necessary. q_back ← (((q_back - 1) % q_capacity) + q_capacity) % q_capacity q_size ← q_size - 1 end procedure