Queues


QUEUES

The queue is an ordered group of elements in which new elements are added at one end (the rear) and elements are removed at the other end (the front).

The queue is known as a FIFO data structure because the first element added is the first element removed -- first in, first out.


A familiar example of a queue is a checkout line in a grocery store. The first person in line is the first to be served. People are served according to the order of their arrival ? first come first served.

A practical example of a queue in computing is the printer queue, which is a list of files to be printed. The first file to be queued is the first to be printed.

Regardless of the implementation of the queue only the elements at the front and rear of the queue are accessible. The middle elements are logically inaccessible.


QUEUE OPERATIONS

There is a group of basic queue operations with which the programmer should be familiar.

1. Determining if the queue is empty before attempting to remove an element. emptyQueue returns TRUE if the queue is empty, FALSE otherwise.
2. Clearing the queue or initializing it to the empty state.
3. Adding an element to the queue. This will be called en-queue (enqueue). The statement enqueue(X) means add item X to the rear of the queue.
4. Removing an element from the queue. This will be called de-queue (dequeue). The statement dequeue(X) means remove the front element from the queue and return it in X. (Note that unlike POP and PUSH for stacks there are no standard names for the addition and removal of elements from queues. They are sometimes called ADD and REMOVE or INSERT and DELETE.)


IMPLEMENTATION

Queues can be implemented in a variety of ways. Stacks and queues can vary greatly in size during run time, and thus are best implemented as dynamic linked lists. The implementation should not affect the code in the higher levels of the program. Only low-level routines like enqueue and dequeue, and the declarations for the data structure will need to be modified. 


Declarations

A queue can be implemented in a linked list by keeping two external pointers to the list -- one to the node on each end.  

 

The class specification appears below.  


   '---------------------------------------------------------------------
   ' linkNode class
   '---------------------------------------------------------------------

   ' instance variables

   Private info As Variant
   Private nextNode As linkNode

   ' class methods

   '---------------------------------------------------------------------
   ' Constructor
   '---------------------------------------------------------------------
   Private Sub Class_Initialize( )
      Set nextNode = Nothing
   End Sub

   '---------------------------------------------------------------------
   ' Set node value
   '---------------------------------------------------------------------
   Public Sub setInfo(ByVal newValue As Variant)
      info = newValue
   End Sub

   '---------------------------------------------------------------------
   ' Return node value
   '---------------------------------------------------------------------
   Public Function getInfo( ) As Variant
      getInfo = info
   End Function

   '---------------------------------------------------------------------
   ' Reset nextNode reference
   '---------------------------------------------------------------------
   Public Sub setNextNode(ByRef followingNode As linkNode)
      Set nextNode = followingNode
   End Sub

   '---------------------------------------------------------------------
   ' Return nextNode reference
   '---------------------------------------------------------------------
   Public Function getNextNode( ) As linkNode
      Set getNextNode = nextNode
   End Function

 


   '---------------------------------------------------------------------
   ' clsQueue class
   '---------------------------------------------------------------------
   Private qFront As linkNode
   Private qRear As linkNode

  
'---------------------------------------------------------------------
   ' Inserts an element at the rear of the queue.
  
'---------------------------------------------------------------------
   Public Sub enqueue(ByVal newValue As Variant)
      Dim Ptr As New linkNode
      Call Ptr.setInfo(newValue)
      Call Ptr.setNextNode(Nothing)

      If qRear Is Nothing Then
         Set qRear = Ptr
         Set qFront = Ptr
      Else
         Call qRear.setNextNode(Ptr)
         Set qRear = Ptr
      End If
   End Sub

  
'---------------------------------------------------------------------
   ' Returns true if queue is empty, false otherwise.
   '---------------------------------------------------------------------
   Public Function emptyQueue( ) As Boolean
      emptyQueue = (qFront Is Nothing) And (qRear Is Nothing)
   End Function

   '---------------------------------------------------------------------
   ' Initializes the queue to the empty state.
   '---------------------------------------------------------------------
   Public Sub clearQueue( )
      Set qFront = Nothing
      Set qRear = Nothing
   End Sub

   '---------------------------------------------------------------------
   ' Removes an element from the front of the queue.
   '---------------------------------------------------------------------
   Public Function dequeue( ) As Variant
      Dim deqNode As linkNode

      If emptyQueue( ) Then
         MsgBox "Queue empty -- no item to dequeue.", vbOKCancel + _
            vbExclamation + vbApplicationModal, "Dequeue Alert"
      Else
         Set deqNode  = qFront
         Set qFront = qFront.getNextNode( )
         dequeue = deqNode .getInfo( )
         Call deqNode.setNextNode( Nothing)
         Set deqNode = Nothing

         If qFront Is Nothing Then Set qRear = Nothing
      End If
   End Function

   '---------------------------------------------------------------------
   ' Return value of the first node in the queue
   '---------------------------------------------------------------------
   Public Function queueTop( ) As Variant
      queueTop = qFront.getInfo( )
   End Function

   '---------------------------------------------------------------------
   ' Cycle through a queue, printing the value of each node
   '---------------------------------------------------------------------
   Public Sub printQueue( )
      Dim Ptr As linkNode
      Set Ptr = qFront
   
      Debug.Print "----- queue contents -----"
      While Not Ptr Is Nothing
         Debug.Print Ptr.getInfo( )
         Set Ptr = Ptr.getNextNode( )
      Wend
   End Sub

 



Stack Operations

CLEAR QUEUE:

Clearing the queue is accomplished by setting qFront and qRear, the external pointers to the queue, to Nothing.  


   '---------------------------------------------------------------------
   ' Initializes the queue to the empty state.
   '---------------------------------------------------------------------
   Public Sub clearQueue( )
      Set qFront = Nothing
      Set qRear = Nothing
   End Sub

 


EMPTY QUEUE:

Testing for an empty queue can be done by checking to see if the external pointers, qFront and qRear, equal Nothing.


   '---------------------------------------------------------------------
   ' Returns true if queue is empty, false otherwise.
   '---------------------------------------------------------------------
   Public Function emptyQueue( ) As Boolean
      emptyQueue = (qFront Is Nothing) And (qRear Is Nothing)
   End Function

 


ENQUEUE

The insertion algorithm for inserting an element at qRear must take care of two cases: when the queue is empty and when it has one or more elements. 


   '---------------------------------------------------------------------
   ' Inserts an element at the rear of the queue.
   '---------------------------------------------------------------------
   Public Sub enqueue (ByVal newValue As Variant)
      Dim newNode As New linkNode
      Call newNode.setInfo(newValue)
      Call newNode.setNextNode(Nothing)

      If qRear Is Nothing Then
         Set qRear = newNode 
         Set qFront = newNode 
      Else
         Call qRear.setNextNode(newNode)
         Set qRear = newNode 
      End If
   End Sub

 

Dim newNode As New linkNode


 

Call newNode.setInfo(newValue)

 

Call qRear.setNextNode( newNode)

 

Set qRear = newNode

 


DEQUEUE

Removing an element from the front of a queue is similar to popping an element from a stack. The only addition is a check to see if the queue is empty after removing the element. If it is, qRear is set to Nothing. 


   '---------------------------------------------------------------------
   ' Removes an element from the front of the queue.
   '---------------------------------------------------------------------
   Public Function dequeue( ) As Variant
      Dim deqNode As linkNode

      If emptyQueue( ) Then
         MsgBox "Queue empty -- no item to dequeue.", vbOKCancel + _
            vbExclamation + vbApplicationModal, "Dequeue Alert"
      Else
         Set deqNode  = qFront
         Set qFront = qFront.getNextNode( )
         dequeue = deqNode .getInfo( )
         Call deqNode.setNextNode(Nothing)
         Set deqNode = Nothing

         If qFront Is Nothing Then Set qRear = Nothing
      End If
   End Function

 

Set deqNode = qFront

 

Set qFront = qFront.getNextNode( )

 

Call deqNode.setNextNode( Nothing)

 

Set deqNode = Nothing

 

<garbage collection>

   



Implementation Note:

Queues can be implemented using a circular linked list. If the external pointer to the list, or queue, points to the last node, both ends of the queue can be accessed. This makes it possible to implement queue operations using one pointer to the queue, rather than separate pointers to the front and rear.

In order to en-queue, the rear node can be accessed through the external pointer , and in order to de-queue, the front node can be accessed through the nextNode field of
queue. An empty queue would be represented by the condition queue Is Nothing.




Applications

Queues are used extensively in operating system software. In multi-user systems the operating system has a job queue of programs waiting to be executed. As each program reaches the front of the queue, its execution is initiated. In addition, many users share many I/O devices and each device has a queue of requests for use.



Test Module


   '---------------------------------------------------------------------
   ' Test module
   '---------------------------------------------------------------------
   Private Sub Form_Load( )
      Dim queue As New clsQueue
      Dim p As Variant

      Call queue.enqueue("A")
      Call queue.printQueue( ) 
      Call queue.enqueue("B")
      Call queue.printQueue( )
      Call queue.enqueue("C")
      Call queue.printQueue( )
      p = queue.dequeue( )
      Call queue.printQueue( )
      p = queue.dequeue( )
      Call queue.printQueue( )
      p = queue.dequeue( )
      Call queue.printQueue( )
      p = queue.dequeue( )
      Call queue.printQueue( )
      Call queue.enqueue("A")
      Call queue.printQueue( )
      Call queue.clearQueue( )
      Call queue.printQueue( )
End Sub