队列是先进先出(FIFO, First In First Out)
队列是只允许在一端删除,在另一端插入的线性表
允许删除的一端叫做队头(front),允许插入的一端叫做队尾(rear)。
目录
队列抽象数据类型(模板)
template <class E>
class Queue {
public:
Queue() { }; //构造函数
~Queue() { }; //析构函数
virtual bool EnQueue(E x) = 0; //进队列
virtual bool DeQueue(E& x) = 0; //出队列
virtual bool getFront(E& x) = 0; //取队头
virtual bool IsEmpty() const = 0; //判队列空
virtual bool IsFull() const = 0; //判队列满
};
队列实现
#include <assert.h>
#include <iostream.h>
#include “Queue.h”
template <class E>
class SeqQueue : public Queue<E> { //队列类定义
protected:
int rear, front; //队尾与队头指针
E *elements; //队列存放数组
int maxSize; //队列最大容量
public:
SeqQueue(int sz = 10); //构造函数
~SeqQueue() { delete[ ] elements; } //析构函数
bool EnQueue(E x); //新元素进队列
bool DeQueue(E& x); //退出队头元素
bool getFront(E& x); //取队头元素值
void makeEmpty() { front = rear = 0; }
bool IsEmpty() const { return front == rear; }
bool IsFull() const
{ return ((rear+1)% maxSize == front); }
int getSize() const
{ return (rear-front+maxSize) % maxSize; }
};
进队出队原则
1.进队时先将新元素按 rear 指示位置加入,再将队尾指针加一 rear = rear + 1。
2.队尾指针指示实际队尾的后一位置。
3.出队时按队头指针指示位置取出元素,再将队头指针进一 front = front + 1, 队头指针指示实际队头位置。
4.队满时再进队将溢出出错(假溢出) ;
5.队空时再出队将队空处理。
6.解决假溢出的办法之一:将队列元素存放数组首尾相接,形成循环(环形)队列。
循环队列(其实就是循环利用空间)
队列存放数组被当作首尾相接的表处理。
队头、队尾指针加1时从maxSize-1直接进到0,可用语言的取模(余数)运算实现。
队头指针进1: front = (front+1) % maxSize;
队尾指针进1: rear = (rear+1) % maxSize;
队列初始化:front = rear = 0;
队空条件:front == rear;
队满条件:(rear+1) % maxSize == front
循环队列判空,判满,置空
void MakeEmpty() { front = rear = 0; }
int IsEmpty() const
{ return front == rear; }
int IsFull() const
{ return (rear+1) % maxSize == front; }
循环队列构造函数
template <class E>
SeqQueue<E>::SeqQueue(int sz)
: front(0), rear(0), maxSize(sz) { //构造函数
elements = new E[maxSize];
assert ( elements != NULL );
};
进队(循环队列)
template <class E>
bool SeqQueue<E>::EnQueue(E x) {
//若队列不满, 则将x插入到该队列队尾, 否则返回
if (IsFull() == true) return false;
elements[rear] = x; //先存入
rear = (rear+1) % maxSize; //非循环队列中就只是尾指针加一,没有取模
return true;
};
出队(循环队列)
template <class E>
bool SeqQueue<E>::DeQueue(E& x) {
//若队列不空则函数退队头元素并返回其值
if (IsEmpty() == true) return false;
x = elements[front]; //先取队头
front = (front+1) % maxSize; //非循环队列中就只是头指针加一,没有取模
return true;
};
返回队头
template <class E>
bool SeqQueue<E>::getFront(E& x) const {
//若队列不空则函数返回该队列队头元素的值
if (IsEmpty() == true) return false; //队列空
x = elements[front]; //返回队头元素
return true;
};
总的来说,循环队列其实难度并不高,难度就在如何去应用实例当中去