8.2 Queue ImplementationSince the queue data structure is simply a specialized list, it is commonly implemented using some type of list structure. There are three common approaches to implementing a queue: using a vector, a linked list, or an array. In the following sections, we examine and compare these three approaches. Python List ImplementationThe simplest way to implement the Queue ADT is to use Python's list. It provides the necessary routines for adding and removing items at the respective ends. By applying these routines, we can remove items from the front of the list and append new items to the end. To use a list for the Queue ADT, the constructor must define a single data field to store the list that is initially empty: class Queue : def __init__(self) : self._qList = list() Figure 8.2.1 illustrates an instance of the class for the queue from Figure 8.1.1. We can test for an empty queue and obtain the size of the queue by examining the length of the list: def isEmpty(self) : return len(self._qList) == 0 def __len__(self) : return len(self._qList) To enqueue an item, we simply append the item to the end of the list: def enqueue(self, item) : self._qList.append(item) The dequeue operation can be implemented by popping and returning the item in the first element of the list: def dequeue(self) : assert not self.isEmpty(), "Can not dequeue from an empty queue." return self._qList.pop(0) Before attempting to remove an item from the list, we must ensure the queue is not empty. Remember, the queue definition prohibits the use of the Program Listing
Since we use list operations to implement the individual queue operations, we need only recall the worst case times for the Python list operations. The size and empty condition operations only require time. The enqueue operation requires time in the worst case since the list may need to expand to accommodate the new item. When used in sequence, the enqueue operation has an amortized cost of . The dequeue operation also requires time since the underlying array used to implement the Python list may need to shrink when an item is removed. In addition, when an item is removed from the front of the list, the following items have to be shifted forward, which requires linear time no matter if an expansion occurs or not. Table 8.2.1 provides a summary of the worst case time-complexities for a queue implemented using a Python list.
Linked List ImplementationA major disadvantage in using a Python list to implement the Queue ADT is the expense of the enqueue and dequeue operations. A better solution is to use a linked list consisting of both head and tail references. Adding the tail reference allows for quick append operations that otherwise would require a complete traversal to find the end of the list. Figure 8.2.2 illustrates a sample linked list with the two external references. The complete implementation of the Queue ADT using a linked list with a tail reference is provided in the listing below. Remember, the individual nodes in the list contain the individual items in the queue. When dequeuing an item, we must unlink the node from the list but return the item stored in that node and not the node itself. An evaluation of the time-complexities is left as an exercise. Program Listing
|