Queue C and Data Structures Baojian Hua
Linear List Recall that a linear list has the form: The delete and insert operations may insert or delete an arbitrary element e_i If the delete is restricted at one end and insert at the other end, we get a queue
Example: Queue of Char ‘a’‘a’ insert ‘b’‘b’ ‘a’‘a’ ‘b’‘b’ ‘a’‘a’ ‘c’‘c’ delete ‘b’‘b’ ‘c’‘c’
Abstract Data Types in C: Interface // in file “queue.h” #ifndef QUEUE_H #define QUEUE_H typedef struct queueStruct *queue; queue newQueue (); int size (queue q); int isEmpty (queue q); void enQueue (queue q, poly x); poly deQueue (queue q); poly getHead (queue q); #endif
Implementation Using Extensible Array // in file “arrayQueue.c” #include “queue.h” struct queueStruct { arrayList l; }; // Recall the box strategy: l q
Operations: “ new ” queue newQueue () { queue q = (queue)malloc (sizeof (*q)); q->l = newArrayList (); return q; } 0 n-1 array max tail l q
Operations: “ size ” int size (queue q) { return arrayListLength (q->l); } 0 n-1 array max tail l q
Operations: “ isEmpty ” int isEmpty (queue q) { return arrayListIsEmpty (q->l); } 0 n-1 array max tail l q
Operations: “ enQueue ” void enQueue (queue q, poly x) { arrayListInsertLast (stk->l, x); return; } 0 n-1 array max tail l q
Operations: “ deQueue ” poly deQueue (queue q) { if (arrayListIsEmpty (q->l)) error (“empty queue”); return arrayListDeleteFirst (q->l); }
Operations: “ deQueue ” 0 n-1 array max tail l q
Operations: “ deQueue ” 0 n-1 array max tail l q
Analysis What ’ s the complexity? enQueue: O(1) deQueue: O(n) data movement Can we do better? Lazy approach better amortized performance Circular queue
Lazy Approach Instead of moving data when “ deQueue ”, we move data only when “ enQueue ” reaching the tail of the queue O(n) on n operations which has O(1) amortized cost
Lazy Approach What ’ s necessary modification? Leave this as a programming assignment 0 n-1 array max tail l q
Circular Queue A refinement of the lazy approach is the circular queue head = tail = 0; tail head enQueue (q, ‘a’);
Circular Queue A refinement of the lazy approach is the circular queue head = tail = 0; tail head enQueue (q, ‘a’); enQueue (q, ‘b’); ‘a’‘a’
Circular Queue A refinement of the lazy approach is the circular queue head = tail = 0; tail head enQueue (q, ‘a’); enQueue (q, ‘b’); enQueue (q, ‘c’); ‘a’‘a’ ‘b’‘b’
Circular Queue A refinement of the lazy approach is the circular queue head = tail = 0; tail head enQueue (q, ‘a’); enQueue (q, ‘b’); enQueue (q, ‘c’); enQueue (q, ‘d’); ‘a’‘a’ ‘b’‘b’ ‘c’‘c’
Circular Queue A refinement of the lazy approach is the circular queue head = tail = 0; tail head enQueue (q, ‘a’); enQueue (q, ‘b’); enQueue (q, ‘c’); enQueue (q, ‘d’); enQueue (q, ‘e’); ‘a’‘a’ ‘b’‘b’ ‘c’‘c’ ‘d’‘d’
Circular Queue A refinement of the lazy approach is the circular queue head = tail = 0; tail head enQueue (q, ‘a’); enQueue (q, ‘b’); enQueue (q, ‘c’); enQueue (q, ‘d’); enQueue (q, ‘e’); ‘a’‘a’ ‘b’‘b’ ‘c’‘c’ ‘d’‘d’ ‘e’‘e’ enQueue (q, ‘f’); ???
Circular Queue A refinement of the lazy approach is the circular queue Empty: head == tail; Full: tail+1 == head ??? General Equations: head = (head+1)%N; tail = (tail+1)%N; tail head ‘a’‘a’ ‘b’‘b’ ‘c’‘c’ ‘d’‘d’ ‘e’‘e’
Circular Queue // Cook these together, we can implement the // input buffer using queue: struct bufferStruct { char buf[128]; int head; int tail; }; struct bufferStruct inputBuffer; // Rethink the key pressing, and “getchar ()”?
Implementation Using Linked List // in file “linkedQueue.c” #include “queue.h” struct queueStruct { linkedList l; }; l q data next data next data next …
Operations: “ new ” queue newQueue () { queue q = (queue)malloc (sizeof (*q)); q->l = newLinkedList (); return q; } l q /\
Operations: “ size ” int size (queue q) { return linkedListLength (q->l); } l q data next data next data next …
Operations: “ isEmpty ” int isEmpty (queue q) { return linkedListIsEmpty (q->l); } l q data next data next data next …
Operations: “ enQueue ” void enQueue (queue q, poly x) { // note the difference with extensible array- // based representation linkedListInsertLast (q->l, x); return; } l q data next data next data next …
Operations: “ deQueue ” poly deQueue (queue) { if (linkedListIsEmpty (q->l)) error (“empty queue”); return linkedListDeleteFirst (q->l); } l q data next data next data next …
Analysis What ’ s the complexity of these operations? enQueue: O(n) search the last element deQueue: O(1) Improvement: Circular linked list leave as programming assignment