(Latest Revision: 02/11/2003)

Hints to Help You Implement the Queue


CONSIDER DECIMAL DIGIT SELECTION:

Suppose you have a decimal display with a capacity of 8 digits. You can then display a number such as:

12938761

If you wish, you can think of this as a queue with 4 numbers on it: 61, 87, 93, and 12.

You can start with an original value of

00000000

When you want enqueue 12 onto the queue, you put the 12 into the rightmost two digits:

00000012

When you want to enqueue 93 onto the queue that already contains 12, you shift the 12 over to the left and put the 93 into the rightmost two digits:

00001293

It's similar to enqueue 87 and then 61

00129387

12938761

If the display is limited to 8 digits, then there is no more room for more elements to be enqueued onto the queue.

At first you may think that you can store any set of four two-digit numbers this way. However what does 00000000 mean? Is this an empty queue or is this a full queue that contains four zeros?

One way to get around this ambiguity is to let 00000000 represent an empty queue, and to agree that we will place only numbers in the range 01-99 on the queue.

How can we program instructions to place an element on the queue? There is a really easy way to do it with arithmetic. For example we can enqueue 87 onto 00001293 by just multiplying by 100 and adding 87:

00001293*100+87 equals 00129387

(It is also fairly easy (though not as easy) to dequeue something using the % and / operators. For example,

00129387 / 10,000 equals 12 (the front element of the queue), and

00129387 % 10,000 equals 00009387 (the queue after the front has been taken off.

(Note: the formula (00129387/10,000) == 12 uses the fact that C-style integer divsion truncates quotients.)

How can you test to see if the queue is full? Well it all really hinges on the fact that 99,999,99 is the largest number that can be stored as an 8-digit non-negative integer.) If the queue is not full you should have room to enqueue any number between 1 and 99. So all you really need to check is whether data*100+99 is more than 99,999,999. (I'm assuming here that data is the name of the unsigned long int you are using for storage.)


MODIFY IT TO WORK ON CHARACTERS:

The idea above works well when you are interested in storing numbers in the range 1-99. It can also work when you want to store characters in the range 'a'-'z'. One could use exactly the scheme described above, except just enqueue numbers in the range 1-26 and ignore the numbers from 27-99. However this wastes space. This queue will probably have a smaller-than-optimal capacity. (Remember: The program specifications require that your implementation have room for at least six characters when the program is compiled and executed on the Sun Ultra's.)

You can conserve capacity better by using a smaller "modulus." There is really nothing special about using modulus 100.

At first glance the queue operations are easier to understand when the modulus is a power of 10. That is because we are accustomed to representing numbers in base-10 notation. However, it's really just as easy to use the same idea with a different modulus. For example, it will work to enqueue by doing data=data*27+code, where code is in the range 1-26. (A modulus of 32 works too. You may prefer to use 32 if you have experience doing C-style bit-operations. That does waste some space, but you can get six letters into a queue using 32 as the modulus.)

Using a modulus of 27, you would put a number between 1 and 26 in the queue. The enqueue operation would have to convert a letter between 'a' and 'z' into a correspondng numerical code before enqueueing: 1 for 'a', 2 for 'b', and so on. Similarly the operations that return the front element of the queue would have to convert the numerical code into the character.

The actual queue storage you will be working with (the class member called data) is an unsigned long int. The maximum value it can store is a constant called ULONG_MAX, which is defined in "limits.h". The value of ULONG_MAX can vary from system to system. Mainly the issue is how many bits are allocated to represent an unsigned long int. The more bits, the larger the number can be before it overflows.

If you are using 27 as your modulus you can test for a full queue by seeing if data*27+26 > ULONG_MAX. However you have to make sure that in the course of doing your test you don't overflow something that the computer is storing as an unsigned long int. In other words, don't directly tell the computer to compute data*27+26 because this will sometimes cause an overflow. If an overflow occurs, the result of the test will not be reliable. Instead, you might cast data to a double first. After that it is safe to multiply by 27 and add 26.


YOU STILL DON'T KNOW HOW YOU ARE GOING TO GET THIS PROGRAM WORKING?:

Come to class and office hours and we can discuss more details. (Please help me by participating in discussions and offering questions and suggestions.)