Array Implementation of a Queue


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

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".

  1. 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.

  2. size()

    Returns the queue size.

  3. empty()

    Returns true if the queue size is 0; otherwise, false.

  4. 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.

  5. front()

    Returns the front item of the queue (q_array[q_front]).

  6. back()

    Returns the back item of the queue (q_array[q_back]).

  7. 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
    
  8. 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
    
  9. 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.

  10. 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.

  11. Destructor

    Deletes the queue array.

  12. 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
    

Double-Ended Queue

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.

  1. 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
    
  2. 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