Imagine an array arranged in a circle: after its last physical cell comes its first cell again. A virtual index continues counting beyond the array’s final index while still referring to an existing physical cell. For an array of size 8, virtual index 8 refers to physical index 0, index 9 refers to 1, and so on. section 9.7
Modulo arithmetic performs the mapping: physical index = virtual index % array size. Thus, 8 % 8 equals 0, allowing a queue’s rear pointer to wrap around without accessing an out-of-bounds index. The queue can reuse cells released by dequeue until the rear reaches the position immediately before the front. section 9.7 section 9.11
Wrapping an enqueue operation
With a capacity of 5, a rear pointer at physical index 4 advances to virtual index 5. Applying 5 % 5 maps it to physical index 0, where the next value can be stored if that cell is free. A compact implementation is `self._rear = (self._rear + 1) % self._max_size`. section 9.11
Resizing complicates the mapping. After changing capacity, the modulo base changes, so old virtual indexes and pointer positions no longer work automatically. Elements must be copied with the queue’s front aligned to index 0 before continuing. section 9.13
def enqueue(self, value):
if self.is_full():
raise ValueError('The queue is already full!')
self._data[self._rear] = value
self._rear = (self._rear + 1) % self._max_size
self._size += 1
Inspect the enqueue implementation that advances the rear pointer with modular arithmetic. section 9.11
