数据结构快速提升(三)----队列【C++实现】

版权声明:本文为博主原创文章,转载请注明出处-- https://blog.csdn.net/qq_38790716/article/details/86476798

完整代码实现 G i t h u b Github ,欢迎大家 f o r k fork s t a r star
S G I SGI S T L STL q u e u e queue 实现STL源码剖析(四)容器适配器–stack、queue

概述

队列( q u e u e queue ):只允许在一端插入操作,而在另一端进行删除操作的线性表

队列是一种先进先出( F i r s t First I n In F i r s t First O u t Out )的线性表,简称 F I F O FIFO 。允许插入的一端称为队尾,允许删除的一端称为队头

在这里插入图片描述

如上图所示,从队尾添加元素称为入队,从队头删除元素称为出队

队列的顺序存储结构

假溢出

使用普通的顺序存储来表示队列容易出现一种问题:假溢出

那什么是假溢出呢?顾名思义,即存储单元并没有真的溢出,而是数据结构表面上的溢出,下面用一张图来说明假溢出
在这里插入图片描述

如上图所示,经过若干操作之后得到上述的队列,很明显这个情况的形成是由于 a 5 a5 的入队,rear指针指向了数组之外,造成了数组越界,而这种情况下 0 0 1 1 却都为空,也即都可以入队,但由于从 f r o n t front 开始,所以只能占据第 4 4 位,随之数组越界。这种现象被叫做“假溢出

这种现象就好像你生活中坐公交车,后排的座位被占满了,前排还有两个座位,然后你下车,想着后排的座位都被占满了,那等下一辆车?
不,当然没有这么笨的人,前面有座位,当然也可以坐了,除非坐满了,才会考虑下一辆车

循环队列

针对于这样的一种现象,我们采取了循环队列来解决假溢出这一问题,循环队列即头尾相接的队列
在这里插入图片描述
但这又带来了一个问题,即空队列的判断条件是 f r o n t = = r e a r front == rear ,现在就如上述情况, f r o n t = r e a r front = rear 时代表了队满,那么应当如何判断此时的队列是满还是空呢?下面给出两种解决方法:

  • 1.设置一个标志变量 f l a g flag ,当 f r o n t = r e a r front = rear f l a g = 0 flag = 0 时队列为空;当 f r o n t = r e a r front = rear f l a g = 1 flag = 1 时队列为满4
  • 2.当队列为空时,条件就是front = rear,当队列为满时,我们修改其条件,保留一个元素空间。也就是说,当队列满时,数组中还有一个空闲单位,即:队满时需满足 ( r e a r + 1 ) (rear + 1) % M A X S I Z E = f r o n t MAXSIZE = front

在这里使用的是第二种方式在这里插入图片描述
通用计算队列长度公式: ( r e a r f r o n t + M A X S I Z E ) (rear - front + MAXSIZE) % M A X S I Z E MAXSIZE

队列是线性表,其操作与线性表的实现类似:

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;  //队头、队尾指针 
};
  1. 队列初始化
template <class DataType>
CirQueue<DataType>::CirQueue() {
	front = rear = 0;
}
  1. 获得队头元素
template <class DataType>
DataType CirQueue<DataType>::GetHead() {
	if (rear == front)
		throw "underflow";
	int i = (front + MAXSIZE) % MAXSIZE;
	return data[i];
}
  1. 入队与出队
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;
}

队列的链式存储

在这里插入图片描述

队头指针( f r o n t front )指向链队列的头结点,队尾指针( r e a r rear )指向终端结点

结点结构:

//节点 
template <class DataType>
struct Node {
	DataType data;
	Node *next;   
};

L i n k Q u e u e LinkQueue :

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;   //队列长度 
};
  1. 队列初始化
template <class DataType>
LinkQueue<DataType>::LinkQueue() {
	Node<DataType> *p = new Node<DataType>;
	p->next = NULL;
	front = rear = p;
	length = 0;
}
  1. 析构
template <class DataType>
LinkQueue<DataType>::~LinkQueue() {
	while (front->next != NULL) {
		Node<DataType> *p = front->next;
		front->next = p->next;
		delete p;
	}
}
  1. 获得队头元素
template <class DataType>
DataType LinkQueue<DataType>::GetHead() {
	if (rear == front)
		throw "underflow";
	DataType tmp = front->next->data;
	return tmp;
}
  1. 入队与出队
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;
}

在可以确定队列长度最大值的情况下,建议用循环队列,无法预估队列的长度时,则用链队列

猜你喜欢

转载自blog.csdn.net/qq_38790716/article/details/86476798