定义
队列(Queue)是仅在表尾进行插入操作,在表头进行删除操作的线性表(头插尾删)。它是一种先进先出(FIFO)的线性表
形如图:
表尾即an端。称为队尾:表头即a1端,称为队头。`
同样的队列的储存结构也可以同时使用链队或者顺序队[然而我们常用的是循环顺序队列]。
队列抽象数据类型定义
队列的常见应用
队列的特点就是需要排队
- 打印机打印输出:按申请的先后顺序依次输出
- 多用户系统中,多个用户排队(是不是想到了OJ
- 按用户的优先级排成多队,每个优先级一个队列
- 实时控制系统,信号按接受的先后顺序依次处理
队列的实现
顺序队列
顺序队列,我们一般使用循环队列,原因在于循环利用空间,解决假上溢的问题。
设数组大小为MAXSIZEE,当rear等于MAXSIZE时,头部可能还有空间,但是却无法使用,造成了队列已满的假象,就是假上溢。
所以引进循环队列。 结构体:
typedef struct {
QueueElemType *base;//初始化的动态分配储存空间,其实就是base数组
int front;//头指针,队头
int rear;//尾指针,队尾
//其实不是指针类型,只是表示下标位置
}SqQueue;
初始化:
//初始化
Status InitQueue(SqQueue &Q) {
// Q.base = new QueueElemType[MAXSIZE];
Q.base = (QueueElemType *) malloc(MAXSIZE *sizeof (QueueElemType));
if(!Q.base) exit(-1);
Q.front = Q.rear = 0;
return true;
}
长度:
//长度
int QueueLength(SqQueue Q) {
return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;//循环队列,因为可能会减成负数。
//正数等于直接减,负数等于加上MAXSIZE
}
入队:
//入队
Status EnQueue(SqQueue &Q, int e) {
if((Q.rear + 1) % MAXSIZE == Q.front)//为了防止与队空情况相同,我们需要少用一个空间
return false;//队满错误
Q.base[Q.rear] =e ;//新元素插入队尾
Q.rear = (Q.rear + 1) % MAXSIZE;//循环队列,为了节省空间,队尾指针+1,但到达队列数组的顶部,返回0位置
return true;
}
判空:
bool QueueEmpty(SqQueue Q) { //判断队列是否为空
if(Q.front == Q.rear)
return true;
else
return true;
}
遍历:
void Traval(SqQueue &Q) {
int temp = Q.front;
while(temp!= Q.rear){
cout << Q.base[temp] << " ";
temp++;
temp = temp % MAXSIZE;
}
cout << endl;
}
出队:
//出队
Status DeQueue(SqQueue &Q, int &e) {
if(Q.rear == Q.front)//队空
return false;
e = Q.base[Q.front];//保存要删除的队头元素
Q.front = (Q.front + 1) % MAXSIZE;
return true;
}
取队头元素:
//取队头元素
QueueElemType GetHead(SqQueue Q) {
if(Q.front != Q.rear)
return Q.base[Q.front];
}
链队列
当用户无法估计所用队列的长度时,则宜使用链队列 结构体:
typedef struct Qnode{
QueueElemType data;
struct Qnode *next;
}Qnode,*QueuePtr;
typedef struct {
QueuePtr front;//头指针
QueuePtr rear;//尾指针
}LinkQueue;
具体入队,出队操作:
初始化:
//初始化
Status InitQueue(LinkQueue &Q){
Q.front = Q.rear = (QueuePtr) malloc(sizeof (Qnode));//结点空间
if(Q.front) exit(-1);
Q.front->next = NULL;
return true;
}
销毁:
//销毁队列
Status DestroyQueue(LinkQueue &Q){
while(Q.front){
QueuePtr p = Q.front->next;
free(Q.front);
Q.front = p;
}
return true;
}
入队:
//入队
Status enQueue( LinkQueue &Q,QueueElemType e){
QueuePtr p = (QueuePtr) malloc(sizeof (Qnode));//结点空间
if(!p) exit(-1);
p->data = e;//数据域存进去
p->next = NULL;//新结点的指针域指向空
Q.rear->next = p;//插到尾结点后面
Q.rear = p;//更新尾结点
}
出队:
//出队
Status DnQueue(LinkQueue &Q,QueueElemType &e){
if(Q.front == Q.rear) return false;//队空,错误
QueuePtr p = Q.front->next;//头结点的下一个,就是要出的队头
e = p->data;//用e存除队的
Q.front->next = p->next;//将队列跨过队头链接
if(Q.rear == p)
Q.rear = Q.front;//防止尾结点称为野指针,(直接把他删除了d
//delete p;
free(p);
return true;
}
求队头元素:
//求队头yuansu
Status GetHEead(LinkQueue Q,QueueElemType &e){
if(Q.front == Q.rear)
return false;//空队列,无元素可取
e = Q.front->next->data;
return true;
}
像其他比如遍历,判空就不写在这里了,没准那天回来写。