UMBC CS 201, Spring 99
UMBC CMSC 201 Spring '99 CSEE | 201 | 201 S'99 | lectures | news | help

The Queue

Implementation using an array

It is quite possible to use an array to implement a queue, but we would suffer all the same space limitations that we have all along with arrays.

We would have to guess about how big the queue could possibly get, declare an array to be of that size, and then start enqueueing items. We would just have to hope that our guess was correct, so that the array could hold the entire queue. Otherwise we'd have to abort the program.

Since in our simple example, this array would be holding ints, we would have to initialize all of the elements of the array to hold some integer that wouldn't be a valid integer for this particular application, possibly 0 or -1.

In this implementation, the pointer head would hold the same address as the name of the array. If the queue is empty, the pointer tail would also hold the same address as the name of the array.

Enqueueing is not a big problem, we would just put a value into the first "empty" element of the array and move the pointer named tail, by using the statement tail = &(array[j]);, where j is the index of the element just filled.

Dequeueing is somewhat of a problem. Since when we dequeue something, it has to be removed from the beginning of the queue (remove array[0]), we will need to move all other values forward by one element in the array. As in:

i = 1; while (array[i] != 0) { array[i - 1] = array[i]; i++; } There dequeueing is quite time consuming.

If we think about implementing the queue using an array, not only are we wasting space, but we are also wasting time. Sometimes it's okay to waste space if it will save us time. Other times it's okay to waste time to save space. It all depends on the needs of the application and there is usually a tradeoff between space and time. It is never okay to waste both space and time. So even though it is possible to implement a queue using an array, it isn't usually done.

Implementation using a linked list

Since we now know about linked lists, we should consider using a linked list implementation of the queue. The queue can be implemented without wasting any space, and by keeping pointers to both the beginning of the list (the head) and the end of the list (the tail), we can make our queue work much faster than an array implementation.

The user interface for the linked list implementation

/************************************************\ * Filename: queue.h * * Author: Sue Bogar * * Date Written: 4/22/98 * * Date modified: 11/28/98 * * Description: This file contains the function * * prototypes to work with queue.c. * * This set of functions provide the operations * * needed including adding an item to the queue, * * enqueue; deleting an item from the queue, * * dequeue; determining if the queue is empty and * * the printing the items in the queue. * * Since the queue is being implemented as a * * linked list, some functions needed for a list * * have been added to this file, although they * * would normally be found in the linked list * * header file. Those functions are CreateNode * * and GetData. * \************************************************/ #ifndef _queue_h #define _queue_h /****************** * This typedef allows us to call the type * of a pointer to a node a nodePtr ******************/ typedef struct tag *nodePtr; /****************** * The queue is being implemented as a linked list * and a linked list requires nodes. Each node is * a structure that has two members, the first to * hold data and the second, of type nodePtr is * a pointer to the next node in the queue. ******************/ typedef struct tag { int data; nodePtr next; }node; /****************** * Enqueue takes two pointers to nodePtrs, and a * nodePtr as arguments. The first argument will * contain the address of head, the second argument * will contain the address of tail, and the third * argument is a pointer to the node to be inserted. * Enqueue will insert the item at the end of the * queue. The addresses of head and tail are passed * into this function, because this function may * need to change the address held in head, and/or * the address held in tail. ******************/ void Enqueue (nodePtr* headPtr, nodePtr* tailPtr, nodePtr temp); /****************** * Dequeue takes two pointers to nodePtr as * its arguments. The first argument will * contain the address of head, the second * argument will contain the address of tail. * This function removes an item from the * queue and returns the data value stored * there. This function may also alter the * address held in either head and/or tail. ******************/ int Dequeue (nodePtr *headPtr, nodePtr *tailPtr); /****************** * IsEmpty takes a nodePtr as its first * argument, which is a pointer to the list, * known as head. It determines whether the * queue is empty and returns 1 (true) if * the queue is empty and 0 (false) if it * is not empty. ******************/ int IsEmpty (nodePtr head); /****************** * PrintQueue takes a nodePtr as an argument * which is initially the head. The queue is * traversed and the value of the data member * of each item is printed. ******************/ void PrintQueue (nodePtr curr); /****************** * CreateNode mallocs the space needed to * hold a struct of type node, initializes * the members, and returns a pointer to * the new node. ******************/ nodePtr CreateNode (void); /****************** * GetData gets the value of data * from the user and puts it into the * node pointed to by the nodePtr it * receives as an argument. ******************/ void GetData (nodePtr temp); #endif

CSEE | 201 | 201 S'99 | lectures | news | help

Sunday, 02-May-1999 13:29:24 EDT