8.3 Circular Array ImplementationThe Python list-based implementation of the Queue ADT is easy to implement, but it requires linear time for the enqueue and dequeue operations. We can improve these times using an array structure and treating it as a circular array. A circular array is simply an array viewed as a circle instead of a line. An example is illustrated in Figure 8.3.1. A circular array allows us to add new items to a queue and remove existing ones without having to shift items in the process. Unfortunately, this approach introduces the concept of a maximum-capacity queue that can become full. A circular array queue implementation is typically used with applications that only require small-capacity queues and allows for the specification of a maximum size. Data OrganizationTo implement a queue as a circular array, we must maintain a count field and two markers. The count field is necessary to keep track of how many items are currently in the queue since only a portion of the array may actually contain queue items. The markers indicate the array elements containing the first and last items in the queue. Consider the following circular array: which illustrates the implementation of the queue from Figure 8.1.1. The figure shows the corresponding abstract and physical views of the circular array. New items are added to the queue by inserting them in the position immediately following the To dequeue an item, the value in the element marked by Notice the remaining items in the queue are not shifted. Instead, only the The queue now contains seven items in elements with one empty slot. What happens if value 39 is added? Since we are using a circular array, the same procedure is used and the new item will be inserted into the position immediately following the This also represents a full queue since all slots in the array are filled. No additional items can be added until existing items have been removed. This is a change from the original definition of the Queue ADT and requires an additional operation to test for a full queue. Queue ImplementationGiven the description of a circular array and its use in implementing a queue, we turn our attention to the implementation details. The constructor creates an object containing four data fields, including the counter to keep track of the number of items in the queue, the two markers, and the array itself: def __init__(self, maxSize) : self._count = 0 self._front = 0 self._back = maxSize - 1 self._qArray = Array(maxSize) Figure 8.3.2 illustrates the circular array when first created by the constructor. The array is created with Figure 8.3.3 illustrates an instance of the class for the queue from Figure 8.1.3. The def isEmpty(self) : return self._count == 0 def __len__(self) : return self._count As indicated earlier, implementing the Queue ADT as a circular array creates the special case of a queue with a maximum capacity, which can result in a full queue. For this implementation of the queue, we must add the def isFull(self) : return self._count == len(self._qArray) To enqueue an item, we must first test the precondition and verify the queue is not full. If the condition is met, the new item can be inserted into the position immediately following the self._back += 1 if self._back == len(self._qArray) : self._back = 0 A simpler approach, however, is to use the modulus operator as part of the increment step. This reduces the need for the conditional and automatically wraps the marker to the beginning of the array as follows: self._back = (self._back + 1) % len(self._qArray) The complete implementation of the enqueue operation is shown below: def enqueue(self, item) : assert not self.isFull(), "Cannot enqueue to a full queue." maxSize = len(self._qArray) self._back = (self._back + 1) % maxSize self._qArray[self._back] = item self._count += 1 The dequeue operation is implemented in a similar fashion as def dequeue(self) : assert not self.isEmpty(), "Cannot dequeue from an empty queue." item = self._qArray[ self._front ] maxSize = len(self._qArray) self._front = (self._front + 1) % maxSize self._count -= 1 return item The item to be removed is taken from the position marked by Program Listing
Run Time AnalysisThe circular array implementation provides a more efficient solution than the Python list. The operations all have a worst case time-complexity of since the array items never have to be shifted. But the circular array does introduce the drawback of working with a maximum-capacity queue. Even with this limitation, it is well suited for some applications.
|