12.7 A queue simulation
) queue: FIFO(first in first out), just like regular queue in the waiting line
) stack: LIFO(last in first out), just like a pile of plates
) The queue class interface
decide a set of attributes of the queue class(the public interface)
) The queue class implementation
use a linked list to represent a queue. A linked list consists of a sequence of nodes, each node contains the information to be held in the list, plus a pointer to the next in the list
struct Node
{
Item item;
struct Node * next;
}
The example code shows a singly linked list because each node has a single link to the next node. The pointer in the last node points to NULL or 0, or with C++11 nullptr keyword.
A data member of the Queue class should point to the first Node of a queue. For convenience, you could also have data members for the last node and the number of nodes in the queue(for quickly adding nodes and detecting full and empty and limit of nodes amount). Also a data member should represent the maximum amount of nodes allowed in the queue.
class Queue
{
private:
struct Node { Item item; struct Node * next;};
enum {Q_SIZE = 10};
Node * front;
Node * rear;
int items;
const int qsize;
...
public:
...
}
) Code:
class Queue
{
private:
struct Node { Item item; struct Node * next;};
...
}
nest the struct in the class, giving it class scope to avoid conflict with STL(standard template library).
) The class methods
Recall that you could only initialize a const variable, rather than assign it to specific value. Thus making the constructor
Queue::Queue(int qs)
{
...
qsize = qs;
}
invalid to assign qsize to qs. For that sake, C++ provides member initializer list:
Queue::Queue(int qs) : qsize(qs)
{
...
}
which follow the regular constructor with the syntax of " : var(val)". You also have to use member initializer list with references for class members. This syntax could only be used with constructors.
Adding members to queue:
1 terminate if the queue is full
2 create a new node
3 place proper values into the node
4 increase the amount of nodes
5 attach the node to the rear of the sequence
Removing members in queue
1 terminate if the queue is empty
2 save the item of the first node to the passed reference to the function
3 decrease Node count
4 save the location of front node(for later deletion)
5 take the node off the queue by "front = front->next"
6 delete former first node
7 if list empty, set rear to NULL
)Other class methods
An explicit destructor which guarantee that a queue would be empty when it expires
A copy constructor and overloading the assignment operator is also required, but you could escape this now:
class Queue
{
private:
Queue(const Queue & q) : qsize(0) { }
Queue & operator=(const Queue & q) { return *this;}
...
}
Define these methods as private prevents outside from accessing the methods, thus forbidding Queue copy and assignment. Pass objects by reference to avoid this problem
) The customer class
You need to use data members to represent the customer's arrive time, process time, and provide a function in the public interface to set the data
Here comes the example:
// queue.h -- interface for a queue
#ifndef QUEUE_H_INCLUDED
#define QUEUE_H_INCLUDED
class Customer
{
private:
long arrive;
int processtime;
public:
Customer() {arrive = processtime = 0;}
void set(long when);
long when() const {return arrive;}
int ptime() const {return processtime;}
};
typedef Customer Item;
class Queue
{
private:
struct Node {Item item; struct Node * next;};
enum {Q_SIZE = 10};
Node * front;
Node * rear;
int items;
const int qsize;
Queue(const Queue & q); // prevent outside access to copy constructor
Queue & operator=(const Queue & q) {return *this;} // prevent outside access to assignment operator
public:
Queue(int qs = Q_SIZE);
~Queue();
bool isempty() const;
bool isfull() const;
int queuecount() const;
bool enqueue(const Item & item);
bool dequeue(Item & item);
};
#endif // QUEUE_H_INCLUDED
// queue.cpp -- Queue and Customer methods
#include "queue.h"
#include <cstdlib>
Queue::Queue(int qs) : qsize(qs)
{
front = rear = NULL;
items = 0;
}
Queue::~Queue()
{
Node * temp;
while (front != NULL)
{
temp = front;
front = front->next;
delete temp;
}
}
bool Queue::isempty() const
{
return items == 0;
}
bool Queue::isfull() const
{
return items == qsize;
}
int Queue::queuecount() const
{
return items;
}
bool Queue::enqueue(const Item & item)
{
if (isfull()) return false;
Node * add = new Node;
add->item = item;
add->next = NULL;
items++;
if (front == NULL)
front = add;
else
rear->next = add;
rear = add;
return true;
}
bool Queue::dequeue(Item & item)
{
if (isempty()) return false;
Node * temp = new Node;
temp = front;
item = front->item;
items--;
front = front->next;
delete temp;
if (items == 0)
rear = NULL;
return true;
}
void Customer::set(long when)
{
processtime = std::rand() % 3 + 1;
arrive = when;
}
// queue.cpp -- Queue and Customer methods
#include "queue.h"
#include <cstdlib>
Queue::Queue(int qs) : qsize(qs)
{
front = rear = NULL;
items = 0;
}
Queue::~Queue()
{
Node * temp;
while (front != NULL)
{
temp = front;
front = front->next;
delete temp;
}
}
bool Queue::isempty() const
{
return items == 0;
}
bool Queue::isfull() const
{
return items == qsize;
}
int Queue::queuecount() const
{
return items;
}
bool Queue::enqueue(const Item & item)
{
if (isfull()) return false;
Node * add = new Node;
add->item = item;
add->next = NULL;
items++;
if (front == NULL)
front = add;
else
rear->next = add;
rear = add;
return true;
}
bool Queue::dequeue(Item & item)
{
if (isempty()) return false;
Node * temp = new Node;
temp = front;
item = front->item;
items--;
front = front->next;
delete temp;
if (items == 0)
rear = NULL;
return true;
}
void Customer::set(long when)
{
processtime = std::rand() % 3 + 1;
arrive = when;
}