完整代码实现 ,欢迎大家 ,
实现STL源码剖析(四)容器适配器–stack、queue
概述
队列( ):只允许在一端插入操作,而在另一端进行删除操作的线性表
队列是一种先进先出( )的线性表,简称 。允许插入的一端称为队尾,允许删除的一端称为队头
如上图所示,从队尾添加元素称为入队,从队头删除元素称为出队
队列的顺序存储结构
假溢出
使用普通的顺序存储来表示队列容易出现一种问题:假溢出
那什么是假溢出呢?顾名思义,即存储单元并没有真的溢出,而是数据结构表面上的溢出,下面用一张图来说明假溢出:
如上图所示,经过若干操作之后得到上述的队列,很明显这个情况的形成是由于 的入队,rear指针指向了数组之外,造成了数组越界,而这种情况下 和 却都为空,也即都可以入队,但由于从 开始,所以只能占据第 位,随之数组越界。这种现象被叫做“假溢出”
这种现象就好像你生活中坐公交车,后排的座位被占满了,前排还有两个座位,然后你下车,想着后排的座位都被占满了,那等下一辆车?
不,当然没有这么笨的人,前面有座位,当然也可以坐了,除非坐满了,才会考虑下一辆车
循环队列
针对于这样的一种现象,我们采取了循环队列来解决假溢出这一问题,循环队列即头尾相接的队列
但这又带来了一个问题,即空队列的判断条件是
,现在就如上述情况,
时代表了队满,那么应当如何判断此时的队列是满还是空呢?下面给出两种解决方法:
- 1.设置一个标志变量 ,当 且 时队列为空;当 且 时队列为满4
- 2.当队列为空时,条件就是front = rear,当队列为满时,我们修改其条件,保留一个元素空间。也就是说,当队列满时,数组中还有一个空闲单位,即:队满时需满足 %
在这里使用的是第二种方式
通用计算队列长度公式: %
队列是线性表,其操作与线性表的实现类似:
const int MAXSIZE = 1000;
template <class DataType>
class CirQueue {
public:
CirQueue(); //初始化
~CirQueue() {} //析构
bool QueueEmpty(); //判断队列是否为空
int QueueLength(); //队列长度
DataType GetHead(); //得到队列头部
void EnQueue(DataType e); //入队
DataType DeQueue(); //出队
private:
DataType data[MAXSIZE];
int front, rear; //队头、队尾指针
};
- 队列初始化:
template <class DataType>
CirQueue<DataType>::CirQueue() {
front = rear = 0;
}
- 获得队头元素:
template <class DataType>
DataType CirQueue<DataType>::GetHead() {
if (rear == front)
throw "underflow";
int i = (front + MAXSIZE) % MAXSIZE;
return data[i];
}
- 入队与出队:
template <class DataType>
void CirQueue<DataType>::EnQueue(DataType e) {
if ((rear + 1) % MAXSIZE == front)
throw "overflow";
data[rear] = e;
rear = (rear + 1) % MAXSIZE;
}
template <class DataType>
DataType CirQueue<DataType>::DeQueue() {
if (rear == front)
throw "underflow";
DataType tmp = data[front];
front = (front + 1) % MAXSIZE;
return tmp;
}
队列的链式存储
队头指针( )指向链队列的头结点,队尾指针( )指向终端结点
结点结构:
//节点
template <class DataType>
struct Node {
DataType data;
Node *next;
};
:
template <class DataType>
class LinkQueue {
public:
LinkQueue(); //初始化
~LinkQueue(); //析构
bool QueueEmpty(); //判断队列是否为空
int QueueLength(); //队列长度
DataType GetHead(); //队头
void EnQueue(DataType e); //入队
DataType DeQueue(); //出队
private:
Node<DataType> *front, *rear; //队头、队尾指针
int length; //队列长度
};
- 队列初始化:
template <class DataType>
LinkQueue<DataType>::LinkQueue() {
Node<DataType> *p = new Node<DataType>;
p->next = NULL;
front = rear = p;
length = 0;
}
- 析构:
template <class DataType>
LinkQueue<DataType>::~LinkQueue() {
while (front->next != NULL) {
Node<DataType> *p = front->next;
front->next = p->next;
delete p;
}
}
- 获得队头元素:
template <class DataType>
DataType LinkQueue<DataType>::GetHead() {
if (rear == front)
throw "underflow";
DataType tmp = front->next->data;
return tmp;
}
- 入队与出队:
template <class DataType>
void LinkQueue<DataType>::EnQueue(DataType e) {
Node<DataType> *p = new Node<DataType>;
p->data = e;
p->next = NULL;
rear->next = p;
rear = p;
++length;
}
template <class DataType>
DataType LinkQueue<DataType>::DeQueue() {
if (front == rear)
throw "underflow";
DataType tmp = front->next->data;
Node<DataType> *p = front;
front = front->next;
delete p;
--length;
return tmp;
}
在可以确定队列长度最大值的情况下,建议用循环队列,无法预估队列的长度时,则用链队列