==============================================================================
C-Scene Issue #3
Queue Pimping
Michael Bacarella
==============================================================================

What is a Queue?

A valid question indeed. A Queue is basically a First In First Out (FIFO) listing of elements that await their turn in an allocated (hopefully) space. Queues are used more often then you might think. Print jobs are queued if something else is currently printing and data received from a device is usually stored up in a queue and wait their turn to be retrieved and used. Not to be confused with a stack, which is Last-in First-Out (simulated by a stack of dishes, and the only way to get to a dish other then the one on top is by removing the ones above it), a queue is usually described as a line at the local DMV, the first person to get on the line is the first person who will be served by the lazy underpaid DMV employee.

Terminology

Queues are sometimes called Ques, and their notation is sometimes used as just Q. (e.g. SQ, RQ, Q_Index) When you add something to the queue, it's known as an en-queue. When you remove something from the queue, it is what we call a de-queue. Simple enough no?

Why would I use a Queue?

Well, here's an example of where I have used a queue before. In a server/client communication algorithm. The user may enter data at any moment in time, and rather then have my program stop what it's doing and service it's needs, I can simply have the data be placed in a queue, and handle it when the time is adequate. Furthermore, if my program can't get to it for a lengthy period of time, the user can still keep entering data into the queue without losing any of it, and this allows you to empty out the queue all at once and send that data onto the server in one blast... provided that this application makes use of multiple threads. :) Still here? Read on!

How do I construct a Queue? (theory)

In theory, the programmer will need to know a few things about the queue. The large chunk of memory doesn't have to be a large chunk at all, if you happen to be fortunate enough to know how to create linked lists (or a similar data structure) you can occupy only as much memory as you need. A pointer to the next avaliable slot can be an integer/char index variable, or in fact a pointer itself. Same goes for first occupied slot. En-Queuing and De-Queuing will require algorithms of some sort, probably ones that look like this:
EnQueue (data)
{
    get the pointer to the end of the queue
    use the pointer to point to the next slot in the
            chunk of memory you set aside for it
    copy the data to that spot
    increment the pointer to the spot which follows it
}

DeQueue
{
    find the beginning of the queue (use the index variable/pointer luke)
    copy that data to something
    increment the index/pointer
    return whatever you copied to something
}
Now you might see a problem with this. If you've been thinking ahead, you might be wondering, "but if you keep incrementing the variable that points to the first in the line of data, won't it just eventually keep getting larger and larger until you overrun the edge of the boundary?".. well, er, yes. But there's a few things you can do to avoid this. If you're making the queue dynamically, you would have to allocate a chunk of memory for each new element you add and free the chunk of memory that you de-queued. This is usually the best way to implement a queue if you have the time/patience to do so. Another variation is if you plan on reading everything from the queue in one fell swoop, keep resetting the the next-free-slot and first-data-element variables to zero when you've completely emptied the queues.

How do I construct a Queue? (implementation)

This code constructs a queue of size 50. Notice the global variables Q_Start and Q_End as well as the QueueData array. You can probably guess what those are for. The 'main' function will read input from the standard input until one of two things happens. The latter won't happen under buffered I/O systems since the program will never know how many keys you have hit until you hit enter/EOF, whence the operating system will finally empty out it's OWN queue and send it all to your program. (See? Queues are everywhere! :)
/* queue.c */
#include <stdio.h>
#define     QUEUE_DEPTH     50

unsigned int     Q_Start;
unsigned int     Q_End;
char    QueuedData[QUEUE_DEPTH];

/* prototypes make compilers happy */
int     EnQueue (char);
char    DeQueue (void);

/* stores data in the queue */
int    EnQueue (char data)
{
    if (Q_End >= QUEUE_DEPTH) {
        fprintf (stderr, "Queue Overflow!");
        return (0);
    }
    QueuedData[Q_End] = data;
    Q_End++;

    /* bounds checking */
    if (Q_End > QUEUE_DEPTH) Q_End = QUEUE_DEPTH;
    return 1;
}

/* returns data from the queue */
char    DeQueue (void)
{
    char    temp;

    if (Q_Start >= QUEUE_DEPTH) {
        return (0);       /* end of queue was reached */
    }
    temp = QueuedData[Q_Start];
    Q_Start++;

    /* bounds checking */
    if (Q_Start > QUEUE_DEPTH) Q_Start = QUEUE_DEPTH;
    return (temp);
}

/* demonstrates the queue */
void    main (void)
{
    char    ch;

    Q_Start = 0;
    Q_End = 0;

    puts ("Enter a string of chars. Signal EOF (Ctrl-Z under DOS) when finished:");

    /* collects chars until EOF is hit or queue is overflowed */
    while ((ch = getchar()) != EOF) {
        if ((EnQueue (ch)) == 0) {
            printf ("\nDumping queue...\n");
            break;
        }
    }
        
    while (ch = DeQueue()) {
        putchar (ch);
    }
    /* at this point, if you wanted to re-use it, you would
       set Q_Start and Q_End to 0 and loop */
}
/* end queue.c */
If I've whet your appetite in any way, and want to see something a little more flexible and awe instilling.. try http://www.psilord.com/defile/queue2.c.

Final Words

Queues are very powerful data structures while being simple in concept and not very durn hard to implement. I find that I'm using them a lot more frequently as of late in my dealings with sockets and graphics programming. They're definitely something worth learning even if you never plan on using them since they appear in the world around us, in computers and elsewhere. (Although it won't help you get to the front of the line at the DMV any more than knowing how the Lottery works will help you win it) I hope this has been of some help. If you have any comments/flames/whatever, please contact me.
This page is Copyright © 1997 By C Scene. All Rights Reserved