SYSC 2006 Winter 2012 Linear Collections: Queues Copyright 2000-2012 D.L. Bailey, Systems and Computer Engineering, Carleton University revised March 20, 2011, November 28, 2011, March 30, 2012
Definition A queue is a collection in which the elements are maintained in the order in which they were added A queue is a first-in, first out (FIFO) collection - the first element is the first one retrieved or removed SYSC 2006 - Queues 2
Abstract View create queue add (enqueue) 5 5 add (enqueue) 3 add (enqueue) 7 remove (dequeue) element (returns 5) remove (dequeue) element (returns 3) queue 7 7 7 3 3 3 5 5 queue SYSC 2006 - Queues 3
Implementing a Queue Because elements are always added at the of the queue, but are retrieved and removed from the of the queue, we should pick a data structure that permits efficient manipulation of both ends of the queue there are no operations that insert elements into or remove elements from the middle of a queue, so efficient access to that part of the data structure is not important SYSC 2006 - Queues 4
Array-Based Queue Data Structure An array-based implementation could be similar to the array-based list struct intarrayqueue { int *elems; int capacity; int size; }; typedef struct intarrayqueue IntQueue; SYSC 2006 - Queues 5
Thinking About the Queue Operations We define elems[0] to be the of the queue and elems[size-1] to be the of the queue enqueue running time will be constant - why? running time will be constant - why? dequeue running time will be proportional to the # of items in the queue why? dequeue would be more efficient (its running time reduced) if elements in the array weren't shifted to the left when the item at position 0 is removed SYSC 2006 - Queues 6
Revised Queue Data Structure struct intarrayqueue { int *elems; int capacity; int size; // # of elements in the Q int ; int ; }; typedef struct intarrayqueue IntQueue; SYSC 2006 - Queues 7
Revised Queue Data Structure is the index of the element in the queue; i.e., the index of the array element from which the next integer will be removed is the index of the element in the queue; i.e., the index of the array element where the last integer was stored SYSC 2006 - Queues 8
Revised Queue Data Structure Initially, is 0, is -1, and size is 0 After 5, 3, 7 have been added to the queue: size 3 0 elems 2 5 3 7 [0] [1] [2]?? [3] [4] SYSC 2006 - Queues 9
Rightward Drift Assume that 5, 3, 7, 2, 8 were added to the queue, and 5 and 3 have been removed from the queue Now, == capacity of queue - 1, but there is room in the queue at the beginning of the array for 2 more elements (elems[0], elems[1]) size 3 2 4 elems?? 7 [0] [1] [2] 2 8 [3] [4] SYSC 2006 - Queues 10
Handling Rightward Drift Approach 1: ensure always == 0 after an element is removed from the queue, shift all remaining elements in the array one position to the left, decrement by 1 (an O(n) algorithm) that's what we wanted to avoid e.g., after adding 5, 3, 7, 2, 8, removing 5, 3: size 3 0 2 elems 7 2 8 [0] [1] [2]?? [3] [4] SYSC 2006 - Queues 11
Handling Rightward Drift Approach 2: shift elements only as required when we try to enqueue an element, if == capacity of queue - 1, shift all elements in the array to the left, then append the element (an O(n) algorithm) e.g., after adding 5, 3, 7, 2, 8, removing 5, 3, then adding 6 size 3 0 3 7 2 8 [0] [1] [2] 6? [3] [4] SYSC 2006 - Queues 12
Handling Rightward Drift Approach 3: visualize the array as a circular array (sometimes called a ring buffer) e.g., a queue with capacity = 8 size 4 2 5 [6] [5] [7] SYSC 2006 - Queues 13 [0] [1] 3 4 [2] 6 3 [4] [3]
Handling Rightward Drift When or reaches capacity of queue -1, its value wraps around to 0 size 7 2 0 [6] [5] [7] 7 3 [4] 2 6 [0] 12 3 [3] [1] 4 [2] SYSC 2006 - Queues 14
Full Queue is one slot ahead of, size == 8 size 8 2 [6] [7] 7 2 [0] 12 9 [1] 1 [5] 3 [4] 6 3 4 [3] [2] SYSC 2006 - Queues 15
Empty Queue is one slot ahead of, size == 0 size 0 2 [6] [7]??? [0]? [1] 1 [5]? [4]??? [3] [2] SYSC 2006 - Queues 16
Construct an Empty Queue IntQueue *intqueue_construct(int capacity) { assert(capacity > 0); IntQueue *qp = malloc(sizeof(intqueue)); assert(qp!= NULL); int *pa = malloc(capacity * sizeof(int)); assert(pa!= NULL); SYSC 2006 - Queues 17
Construct an Empty Queue } qp->data = pa; qp->capacity = capacity; qp->size = 0; qp-> = 0; qp-> = capacity - 1; return qp; SYSC 2006 - Queues 18
Determining the Queue's State _Bool intqueue_is_empty(const IntQueue *qp) { assert(qp!= NULL); return qp->size == 0; } _Bool intqueue_is_full(const IntQueue *qp) { assert(qp!= NULL); return qp->size == qp->capacity; } SYSC 2006 - Queues 19
Determining the Queue's State int intqueue_size(const IntQueue *qp) { assert(qp!= NULL); return qp->size; } SYSC 2006 - Queues 20
Insert/Retrieve/Remove Elements intqueue_enqueue() returns true if an element was inserted, false if the queue is full (element not inserted) intqueue_() returns true if an integer was retrieved (and assigned to the variable pointed to by parameter element), false if the queue is empty intqueue_dequeue() returns true if an integer was retrieved and removed (and assigned to the variable pointed to by parameter element), false if the queue is empty SYSC 2006 - Queues 21
Insert an Element into a Queue _Bool intqueue_enqueue(intqueue *qp, int element) { assert(qp!= NULL); if (intqueue_is_full(qp)) return false; qp-> = (qp-> + 1) % qp->capacity; qp->data[qp->] = element; qp->size++; return true; } SYSC 2006 - Queues 22
Retrieve an Element from a Queue _Bool intqueue_(intqueue *qp, int *element) { assert(qp!= NULL); if (intqueue_is_empty(qp)) return false; *element = qp->data[qp->]; return true; } SYSC 2006 - Queues 23
Remove an Element from a Queue _Bool intqueue_dequeue(intqueue *qp, int *element) { assert(qp!= NULL); if (intqueue_is_empty(qp)) return false; *element = qp->data[qp->]; qp-> = (qp-> + 1) % qp->capacity; qp->size--; return true; } SYSC 2006 - Queues 24