1. 概念
队列本质上是特殊的线性表,它是在一端(队头)进行删除操作,另一端(队尾)进行插入操作,遵守先进先出规则(FIFO)。既然队列也是线性表,当然也有两种数据存储方式:顺序存储结构,这种结构事先要基本确定队列的大小,不支持动态分配存储空间,所以插入和删除元素比较省时,但是会造成空间的浪费。 为了节省空间,后来学者提出了循环队列;链式存储结构,可以不需要事先知道队列的大小,支持动态和释放空间,但是插入和删除操作比较耗时,也称链队列。其中有循环队列也可分为两种:顺序存储结构循环队列 、链式结构循环队列。【链表优势:空间无限理论上】
2. 顺序存储结构队列
2.1 抽象数据类型
/*
InitQueue(*Q); //初始化一个空队列
DestroyQueue(*Q); //队列存在,则销毁
ClearQueue(*Q); //将队列清空
QueueEmpty(Q); //队列为空,返回true or flase
GetHead(Q,*e); //队列存在且非空,返回队列的头元素
InsertQueue(*Q,e); //队列存在,插入元素e到Q中并成为队尾元素
DeleteQueue(*Q,*e); //删除队列头元素,并以e返回
QueueLength(Q); //返回队列的元素个数
*/
//队列的顺序存储结构与线性表顺序结构相同
struct QUEUE{
ElemType data[MAXSIZE]; //数据域
int length; //长度
};
2.2 初始化、插入以及删除操作
1)初始化就是开辟空间,清理内存以及更新长度
2)插入队列的插入只能是从尾端进行,时间复杂度为O(1)
3)删除操作时只能在队列头部进行,后面所有数据要向前移动,时间复杂度O(n)
//初始化队列
void Qq::InitQueue(QUEUE &q)
{
q.length = 0;
for (int i = MAXSIZE - 1; i >= 0; i--)
q.data[i] = 0;
}
//插入数据队列
Qq::Status Qq::InsertQueue(QUEUE &q, ElemType e)
{
if (q.length == MAXSIZE)
return ERROR;
q.data[q.length] = e;
q.length++;
return OK;
}
//删除数据队列
Qq::Status Qq::DeleteQueue(QUEUE &q, ElemType &e)
{
if (q.length < 1)
return ERROR;
e = q.data[0];
for (int i = 1; i <= q.length; i++)
q.data[i - 1] = q.data[i];
q.length--;
return OK;
}
3. 链式存储结构队列
4. 顺序存储结构循环队列
4.1 抽象数据类型
//队列的顺序存储结构与线性表顺序结构相同
struct RQUEUE{
ElemType data[MAXSIZE]; //数据空间
int front; //头指针
int rear; //尾指针
};
1) 这里就存在一个问题:怎么判断循环队列是满了的?
**方法1:**设置一个标志flage,当 front = rear时且flage=0,队列为空;当当 front = rear时且flage=1,队列为满。
**方法2:**当front = rear时为空,队列满时,我们修改其条件保留一个空间。也就是,队列满时队列还有一空闲空间。
4.2 初始化、插入以及删除操作
1)队列满时条件判断:(rear+1)%QueueSize==front,其中QueueSize指队列的最大尺寸
2)队列元素长度:(rear-front+QueueSize)%QueueSize
//初始化循环顺序结构队列
void RQq::InitQueue(RQUEUE &q)
{
q.front = 0;
q.rear = 0;
}
//返回循环队列长度
int RQq::QueueLength(RQUEUE q)
{
return (q.rear - q.front + MAXSIZE) % MAXSIZE;
}
//插入元素到循环队列rear
RQq::Status RQq::InsertQueue(RQUEUE &q, ElemType e)
{
if ((q.rear + 1) % MAXSIZE == q.front) //满队列
return ERROR;
q.data[q.rear] = e; //插入到尾指针
q.rear = (q.rear + 1) % MAXSIZE; //更新尾指针位置
return OK;
}
//删除循环队列元素front
RQq::Status RQq::DeleteQueue(RQUEUE &q, ElemType &e)
{
if (q.rear == q.front) //队列为空
return ERROR;
e = q.data[q.rear]; //删除的数据
q.front = (q.front + 1) % MAXSIZE; //更新头指针
return OK;
}