基本概念
队列是仅在表尾部进行插入操作,在表头进行删除操作的线性表。表尾即 an 端,称为队尾,表头即 a1 端,称为队头。它是一种先进先出 (FIFO) 的线性表
- 入队:在表尾部插入元素
- 出队:从表头删除元素
存储结构
队列的存储结构分为链式队列和顺序队列 (常用循环顺序队列)
栈空
front == rear(不一定为零)
入栈
出栈
front == rear 此时栈为空
栈满
如果用 front 指针和 rear 指针重合表示栈满,与栈空冲突
所以少用一个元素空间,当 (rear + 1 == front) % MAX_CNT 时表示栈满
循环特性
栈中元素个数计算公式 :
cnt = (rear - front + MAX_CNT) % MAC_CNT
加入 MAX_CNT = 5,则上图栈中元素个数为:(0-2+5) % 5 =3
应用
- 脱机打印输出,按申请的先后顺序依次输出
- 多用户系统中,多个用户排成队,分时地循环使用 CPU 和内存
- 按用户的优先级排成多个队,每个优先级一个队列
- 实时控制系统中,信号按接收的先后顺序依次处理
- 网络电文传输,按到达的时间先后顺序依次进行
程序实现
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status;
typedef int Boolean;
typedef int QElemType;
/**
* @brief queue_length + 1. if(rear + 1 == front) queue is full.
*
*/
#define MAX_QSIZE 5
typedef struct SqQueue
{
QElemType *base; /**< 初始化的动态分配存储空间 */
int front; /**< 头指针,若队列不空,指向队列头元素 */
int rear; /**< 尾指针,若队列不空,指向队列尾元素的下一个位置 */
char over_writable; /**< 队列满之后是否能够继续入队 */
} SqQueue;
// 顺序循环队列的基本操作 (9 个)
/* 队列的初始化
font = rear = 0
over_writable = 0 队列满之后默认不支持继续入队
*/
void InitQueue(SqQueue *Q)
{ // 构造一个空队列 Q
Q->base = (QElemType *)malloc(MAX_QSIZE * sizeof(QElemType));
if (!Q->base) // 存储分配失败
exit(-1);
Q->front = Q->rear = 0;
Q->over_writable = 1;
return;
}
void DestroyQueue(SqQueue *Q)
{ // 销毁队列 Q,Q 不再存在
if (Q->base)
free(Q->base);
Q->base = NULL;
Q->front = Q->rear = 0;
return;
}
void ClearQueue(SqQueue *Q)
{ // 将 Q 清为空队列
Q->front = Q->rear = 0;
return;
}
/* 空队标志 font == rear */
Status QueueEmpty(SqQueue Q)
{ // 若队列 Q 为空队列,则返回 TRUE;否则返回 FALSE
if (Q.front == Q.rear) // 队列空的标志
return TRUE;
else
return FALSE;
}
int QueueLength(SqQueue Q)
{ // 返回 Q 的元素个数,即队列的长度
return (Q.rear - Q.front + MAX_QSIZE) % MAX_QSIZE;
}
Status GetHead(SqQueue Q, QElemType *e)
{ // 若队列不空,则用 e 返回 Q 的队头元素,并返回 OK;否则返回 ERROR
if (Q.front == Q.rear) // 队列空
return ERROR;
*e = Q.base[Q.front];
return OK;
}
Status EnQueue(SqQueue *Q, QElemType e)
{ // 插入元素 e 为 Q 的新的队尾元素
if ((Q->rear + 1) % MAX_QSIZE == Q->front) /* 队列满 少用一个元素的空间 尾指针再加 1 和头指针重合,就认为队列已满 */
{
if (0 == Q->over_writable)
return ERROR;
else
Q->front = (Q->front + 1) % MAX_QSIZE; /* 删除队头的元素,后面继续入队 */
}
Q->base[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAX_QSIZE;
return OK;
}
Status DeQueue(SqQueue *Q, QElemType *e)
{ // 若队列不空,则删除 Q 的队头元素,用 e 返回其值,并返回 OK;否则返回 ERROR
if (Q->front == Q->rear) // 队列空
return ERROR;
*e = Q->base[Q->front];
Q->front = (Q->front + 1) % MAX_QSIZE;
return OK;
}
void QueueTraverse(SqQueue Q, void (*vi)(QElemType))
{ // 从队头到队尾依次对队列 Q 中每个元素调用函数 vi()
int i;
i = Q.front;
while (i != Q.rear)
{
vi(Q.base[i]);
i = (i + 1) % MAX_QSIZE;
}
printf(" \n");
return;
}
void print(QElemType i)
{
printf("%d", i);
return;
}
int main(int argc, char *argv[])
{
int i;
QElemType d;
SqQueue q;
InitQueue(&q);
printf("queue is empty ? %d(1 : yes; 0 : no)", QueueEmpty(q));
printf("queue len is %d\n", QueueLength(q));
EnQueue(&q, -5);
EnQueue(&q, 5);
EnQueue(&q, 7);
printf("insert 3 value(-5 5 10) queue len is %d\n", QueueLength(q));
printf("queue is empty ? %d(1 : yes; 0 : no)", QueueEmpty(q));
EnQueue(&q, 1);
EnQueue(&q, 2);
printf("\r\nqueue value is");
QueueTraverse(q, print);
i = GetHead(q, &d);
if (i == OK)
printf("front value is %d\n", d);
DeQueue(&q, &d);
printf("delete front value %d\n", d);
i = GetHead(q, &d);
if (i == OK)
printf("new front value is %d\n", d);
ClearQueue(&q);
printf("clear queue q.front=%u q.rear=%u \n", q.front, q.rear);
DestroyQueue(&q);
printf("destroy queue q.front=%u q.rear=%u\n", q.front, q.rear);
return 1;
}
/**
* 编译:gcc test.c -0 test
* 执行:./test
* 结果:
* queue is empty ? 1(1 : yes; 0 : no)queue len is 0
* insert 3 value(-5 5 10) queue len is 3
* queue is empty ? 0(1 : yes; 0 : no)
* queue value is5712
* front value is 5
* delete front value 5
* new front value is 7
* clear queue q.front=0 q.rear=0
* destroy queue q.front=0 q.rear=0
*/
/************************** end of file *******************************/