(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.)