Queues

Introduction

The key definition of a stack is LIFO A queue is somewhat related but the key concept is First In, First Out, FIFO The word queue must be of French origin given its spelling. In New York people stand on line at the theater, in America, people stand in line and in England, they queue up.

A queue needs two pointers, front and rear. It also uses four routines like stacks. Items are added at the rear and removed at the front. So we have an enqueue() and an unqueue*( method. I called it unqueue() because there is yet another datastructure called a dequeue and I didn't want to confuse the name.

Uses

Queues are normally used in operating systems for scheduling various tasks. Often there is more than one for a given resource to allow priorities. They can be used as a kind of buffer, for message passing between processes and in simulations.

Implementation

The implementation we will see is using a list. We are using the STL list container so we can use the methods on that object to do most of the work. The queue operations turn into list method calls.

This is the class structure
template 
class queue
{
	public:
		void enqueue(TYPE x) { cue.push_back(x);}
		TYPE unqueue() { TYPE x = cue.front(); cue.pop_front(); return x;}
		int size() { return cue.size();}
		bool isEmpty() { return cue.empty();}
		friend ostream & operator<<(ostream & os, queue & q)
		{
			list::iterator ptr = q.cue.begin();
			while(ptr != q.cue.end())
				os << *ptr++ << ' ';
			os << endl;
			return os;
		}
	private:
		list cue;
};
Note that there is no method to determine if the queue is full. This can only happen if the underlying list is full which happens only if there is no memory. This would be best handled by eceptions.

Here is a simple main() to show the operations of the queue.

int main(int argc, char* argv[])
{
	queue Q;
	int i;

	if(Q.isEmpty()) 
		cout << "Queue is initially empty" << endl;
	else
		cout << "Queue is initially NOT empty" << endl;

	for(i=0; i< 10; i++)
		Q.enqueue(i);

	if(Q.isEmpty()) 
		cout << "Queue is empty after push loop" << endl;
	else
		cout << "Queue is NOT empty after push loop" << endl;

	
	cout << "contents of the queue using operator<<" << endl;
	cout << Q << endl;

	cout << "Size of queue before unqueue loop is " << Q.size() << endl;

	cout << "contents of the queue while emptying it" << endl;
	while(! Q.isEmpty()) {
		cout << Q.unqueue() << ' ';
	} // while
	cout << endl;

	cout << "Size of queue after unqueue loop is " << Q.size() << endl;
	return 0;
}
And here is the output from the above code. Note that the numbers come out in the same order they went in.
Queue is initially empty
Queue is NOT empty after push loop
contents of the queue using operator<<
0 1 2 3 4 5 6 7 8 9

Size of queue before unqueue loop is 10
contents of the queue while emptying it
0 1 2 3 4 5 6 7 8 9
Size of queue after unqueue loop is 0
Press any key to continue

Circular Queues

Sometimes we want to go around and around over the same items. For example, if we have a queue of processes in an operating system. In this case, we would make the end of the list point back to the beginning. This is a little difficult using the STL so we won't implement that here. But you should be aware that you can have circular queues.