队列
队列queue也是一种线性表,但它被限制为只能在队尾插入,称为入队操作(enqueue),从队首删除,称为出队操作(dequeue),因此也被称为FIFO线性表,即先进先出。
队列的ADT
template <typename E> class Queue {
private:
void operator =(const Queue&) {} // Protect assignment
Queue(const Queue&) {} // Protect copy constructor
public:
Queue() {} // Default
virtual ~Queue() {} // Base destructor
// Reinitialize the queue. The user is responsible for
// reclaiming the storage used by the queue elements.
virtual void clear() = 0;
// Place an element at the rear of the queue.
// it: The element being enqueued.
virtual void enqueue(const E&) = 0;
// Remove and return element at the front of the queue.
// Return: The element at the front of the queue.
virtual E dequeue() = 0;
// Return: A copy of the front element.
virtual const E& frontValue() const = 0;
// Return: The number of elements in the queue.
virtual int length() const = 0;
};
如果使用普通的顺序表来实现队列,就会导致enqueue和dequeue操作中,一个时间代价为Θ(n),另一个为Θ(1),分别对应队首队尾正放与倒放的情况。
因此采用一种循环顺序表的方式来实现,即顺序表的最后一个结点的next指针指向head,且每次enqueue操作使得front后移,dequeue操作使得rear也后移。
这带来一个小问题,就是对于一个有着n长度的顺序表来说,它应该能表示n+1种状态,但是由于front和rear各指向一个位置,导致实际上只能表示n种状态,这就是的第一种状态,空状态,和第n+1种状态,满状态的区分上产生了困难,一种解决方法是单独设置一个布尔成员变量,用来记录是否为空,或者将顺序表长度设为n+1,只在其中保存最多n个元素,便可表示,n+1种状态。
链式队列
一种简单修改后的链表,只是固定front和rear指针指向链表的的头和尾,但是只能在front处删除,在rear处添加,而初始化时,将front和rear均指向头结点。
链式队列的实现:
template <typename E> class LQueue: public Queue<E> {
private:
Link<E>* front; // Pointer to front queue node
Link<E>* rear; // Pointer to rear queue node
int size; // Number of elements in queue
public:
LQueue(int sz =defaultSize) // Constructor
{ front = rear = new Link<E>(); size = 0; }
~LQueue() { clear(); delete front; } // Destructor
void clear() { // Clear queue
while(front->next != NULL) { // Delete each link node
rear = front;
delete rear;
}
rear = front;
size = 0;
}
void enqueue(const E& it) { // Put element on rear
rear->next = new Link<E>(it, NULL);
rear = rear->next;
size++;
}
E dequeue() { // Remove element from front
Assert(size != 0, "Queue is empty");
E it = front->next->element; // Store dequeued value
Link<E>* ltemp = front->next; // Hold dequeued link
front->next = ltemp->next; // Advance front
if (rear == ltemp) rear = front; // Dequeue last element
delete ltemp; // Delete link
size --;
return it; // Return element value
}
const E& frontValue() const { // Get front element
Assert(size != 0, "Queue is empty");
return front->next->element;
}
virtual int length() const { return size; }
};