E2. What is wrong with the following attempt to use the copy constructor to im- plement the overloaded assignment operator for a linkedStack?
voidStack:: operator= (constStack&original)
{
Stack new_copy(original);
top_node = new_copy.top_node;
}
How can we modify this code to give a correct implementation?
4.4 LINKED QUEUES
In contiguous storage, queues were significantly harder to manipulate than were stacks, because it was necessary to treat straight-line storage as though it were arranged in a circle, and the extreme cases of full queues and empty queues caused difficulties. It is for queues that linked storage really comes into its own. Linked queues are just as easy to handle as are linked stacks. We need only keep two pointers,frontandrear, that will point, respectively, to the beginning and the end of the queue. The operations of insertion and deletion are both illustrated in Figure 4.13. 102 front rear Added to Removed from front of queue queue rear of X X X
Figure 4.13. Operations on a linked queue
4.4.1 Basic Declarations
For all queues, we denote byQueue_entrythe type designating the items in the queue. For linked implementations, we declare nodes as we did for linked struc- tures inSection 4.1.3and use atypedefstatement to identify the typesQueue_entry
andNode_entry. In close analogy to what we have already done for stacks, we ob-
tain the following specification: typeQueue
101
classQueue{ public:
// standard Queue methods
Queue( );
boolempty( )const;
Error_code append(constQueue_entry&item);
Error_code serve( );
Error_code retrieve(Queue_entry&item)const; // safety features for linked structures
∼Queue( );
Queue(constQueue&original);
void operator= (constQueue&original); protected:
Node*front,*rear; };
The first constructor initializes a queue as empty, as follows: initialize
Queue::Queue( )
/*Post: The Queue is initialized to be empty.*/ {
front = rear =NULL; }
Let us now turn to the method to append entries. To add an entryitemto the rear of a queue, we write:
103
Error_code Queue::append(constQueue_entry&item)
/*Post: Add item to the rear of the Queue and return a code of success or return a code of overflow if dynamic memory is exhausted.*/
{
Node*new_rear =newNode(item);
if(new_rear == NULL)returnoverflow;
if(rear == NULL) front = rear = new_rear; else{
rear->next = new_rear;
rear = new_rear; }
returnsuccess; }
The cases when the Queueis empty or not must be treated separately, since the addition of aNodeto an emptyQueuerequires setting bothfrontandrearto point to the newNode, whereas addition to a nonemptyQueuerequires changing only
Section 4.4 • Linked Queues
139
To serve an entry from the front of aQueue, we use the following function:
Error_code Queue::serve( )
/*Post: The front of the Queue is removed. If the Queue is empty, return an
Error_code of underflow.*/ {
if(front == NULL)returnunderflow;
Node*old_front = front;
front = old_front->next; if(front == NULL) rear =NULL; deleteold_front;
returnsuccess; }
Again the possibility of an emptyQueuemust be considered separately. Any at- tempt to delete from an emptyQueueshould generate anError_codeofunderflow. It is, however, not an error for the Queueto become empty after a deletion, but
thenrearandfrontshould both becomeNULLto indicate that theQueuehas become
empty. We leave the other methods of linked queues as exercises.
If you compare these algorithms for linked queues with those needed for con- tiguous queues, you will see that the linked versions are both conceptually easier and easier to program. We leave overloading the assignment operator and writing the destructor and copy constructor for aQueueas exercises.
4.4.2 Extended Linked Queues
Our linked implementation of aQueueprovides the base class for other sorts of queue classes. For example, extended queues are defined as in Chapter 3. The following C++ code defining a derived classExtended_queueis identical to the corresponding code ofChapter 3.
104
classExtended_queue: publicQueue{ public:
boolfull( )const; intsize( )const; voidclear( );
Error_code serve_and_retrieve(Queue_entry&item); };
Although thisclassExtended_queuehas a linked implementation, there is no need to supply explicit methods for the copy constructor, the overloaded assignment operator, or the destructor. For each of these methods, the compiler generates a default method
implementation default implementation. The default method calls the corresponding method of the baseQueueobject. For example, the default destructor for anExtended_queue
merely calls the linkedQueuedestructor: This will delete all dynamically allocated
Extended_queuenodes. Because ourclassExtended_queuestores no linked data
that is not already part of the class Queue, the compiler generated-defaults are exactly what we need.
The declared methods for the linkedclassExtended_queueneed to be repro- grammed to make use of the linked data members in the base class. For example, the new methodsizemust use a temporary pointer calledwindowthat traverses
theQueue(in other words, it moves along theQueueand points at eachNodein
sequence).
104
intExtended_queue::size( )const
/*Post: Return the number of entries in the Extended_queue.*/ {
Node*window = front;
intcount = 0;
while(window!=NULL){
window = window->next;
count++; }
returncount; }
The other methods for the linked implementation of an extended queue are left as exercises.
Exercises 4.4
E1. Write the following methods for linked queues: (a) the methodempty,(b) the methodretrieve, (c) the destructor,
(d) the copy constructor,
(e) the overloaded assignment opera- tor.
E2. Write an implementation of theExtended_queuemethodfull. In light of the simplicity of this method in the linked implementation, why is it still important to include it in the linkedclassExtended_queue?
E3. Write the following methods for the linkedclassExtended_queue:
(a) clear; (b) serve_and_retrieve;
E4. For a linked Extended_queue, the functionsize requires a loop that moves through the entire queue to count the entries, since the number of entries in the queue is not kept as a separate member in the class. Consider modifying the declaration of a linkedExtended_queueto add a count data member to the class. What changes will need to be made to all the other methods of the class? Discuss the advantages and disadvantages of this modification compared to the original implementation.
E5. Acircularly linked list, illustrated inFigure 4.14, is a linked list in which the node at the tail of the list, instead of having aNULLpointer, points back to the node at the head of the list. We then need only one pointertailto access both ends of the list, since we know thattail->nextpoints back to the head of the list.
(a) If we implement a queue as a circularly linked list, then we need only one pointertail(orrear) to locate both the front and the rear. Write the methods needed to process a queue stored in this way.
(b) What are the disadvantages of implementing this structure, as opposed to using the version requiring two pointers?