什么是队列
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
队列这个概念非常好理解。你可以把它想象成排队买票,先来的先买,后来的人只能站末尾,不允许插队。先进者先出,这就是典型的“队列”。
我们知道,CPU 资源是有限的,任务的处理速度与线程个数并不是线性正相关。相反,过多的线程反而会导致 CPU 频繁切换,处理性能下降。所以,线程池的大小一般都是综合考虑要处理任务的特点和硬件环境,来事先设置的。当我们向固定大小的线程池中请求一个线程时,如果线程池中没有空闲资源了,这个时候线程池如何处理这个请求?是拒绝请求还是排队请求?各种处理策略又是怎么实现的呢?
看完下面队列C语言实现,相信你会多少有些了解
队列只支持两个基本操作:入队 enqueue(),放一个数据到队列尾部;出队 dequeue(),从队列头部取一个元素。
队列跟栈一样,也是一种操作受限的线性表数据结构。
顺序队列和链式队列
队列跟栈一样,也是一种抽象的数据结构。它具有先进先出的特性,支持在队尾插入元素,在队头删除元素。
跟栈一样,队列可以用数组来实现,也可以用链表来实现。用数组实现的栈叫作顺序栈,用链表实现的栈叫作链式栈。同样,用数组实现的队列叫作顺序队列,用链表实现的队列叫作链式队列。
随着不停地进行入队、出队操作, front 和 rear 都会持续往后移动。当 rear 移动到最右边,即使数组中还有空闲空间,也无法继续往队列中添加数据了。同时也不好判断队满条件,可以使用循环队列来实现
循环队列
循环队列,顾名思义,它长得像一个环。原本数组是有头有尾的,是一条直线。现在我们把首尾相连,扳成了一个环。
经过推算,可以发现:
队空 Q.rear==Q.front。
队满 (Q.rear+1)%MAXSIZE==Q.front。
注意,当队列满时,图中的 Q.rear 指向的位置实际上是没有存储数据的。所以,循环队列会浪费一个数组的存储空间。
循环队列实现
队列结构设计
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;
typedef int QElemType; /* QElemType类型根据实际情况而定,这里假设为int */
/* 循环队列的顺序存储结构 */
typedef struct {
QElemType data[MAXSIZE];
int front;//头指针(记录位置,非指针变量)
int rear;//尾指针,若队列不空,指向队列尾元素的下一个位置,即待入队位置
}SqQueue;
1.初始化空队列
/* 1.初始化空队列 */
Status initQueue(SqQueue *Q) {
Q->front = 0;
Q->rear = 0;
return OK;
}
2.清空队列
/* 2.清空队列 */
Status clearQueue(SqQueue *Q) {
Q->front = 0;
Q->rear = 0;
return OK;
}
/* 3.判断队空 */
int QueueEmpty(SqQueue Q) {
if (Q.front == Q.rear)
return TRUE;
else
return FALSE;
}
4.判断队满
/* 4.判断队满 */
int QueueFull(SqQueue Q) {
if ((Q.rear+1)%MAXSIZE == Q.front)
return TRUE;
return FALSE;
}
5.入队
/* 5.入队 */
Status enQueue(SqQueue *Q, QElemType e) {
//判断队满
if (QueueFull(*Q))
return ERROR;
Q->data[Q->rear] = e;//将元素e赋值给队尾
//rear向后移动一位,%保证循环
Q->rear = (Q->rear+1)%MAXSIZE;
return OK;
}
6.出队
/* 6.出队 */
Status deQueue(SqQueue *Q, QElemType *e) {
//判断队空
if (QueueEmpty(*Q))
return ERROR;
//将队头元素赋值给e
*e = Q->data[Q->front];
//front 指针向后移动一位,若到最后则转到数组头部
Q->front = (Q->front+1)%MAXSIZE;
return OK;
}
7.获取队列当前元素个数
/* 7.队列当前元素个数 */
int QueueLength(SqQueue Q){
return (Q.rear - Q.front + MAXSIZE)%MAXSIZE;
}
8.若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR
/* 8.若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR; */
Status GetHead(SqQueue Q,QElemType *e){
if (QueueEmpty(Q))
return ERROR;
*e = Q.data[Q.front];
return OK;
}
9.从队头到队尾依次对队列的每个元素数组
/* 9.从队头到队尾依次对队列的每个元素数组 */
Status QueueTraverse(SqQueue Q){
int i;
i = Q.front;
while (i != Q.rear) {
printf("%d ",Q.data[i]);
i = (i+1)%MAXSIZE;
}
printf("\n");
return OK;
}
10.主函数中验证
int main(int argc, const char * argv[]) {
printf("链队列的表示与操作!\n");
Status iStatus;
QElemType d;
LinkQueue q;
//1.初始化队列q
iStatus = InitQueue(&q);
//2. 判断是否创建成
if (iStatus) {
printf("成功地构造了一个空队列\n");
}
//3.判断队列是否为空
printf("是否为空队列?%d (1:是 0:否)\n",QueueEmpty(q));
//4.获取队列的长度
printf("队列的长度为%d\n",QueueLength(q));
//5.插入元素到队列中
enQueue(&q, -3);
enQueue(&q, 6);
enQueue(&q, 12);
printf("队列的长度为%d\n",QueueLength(q));
printf("是否为空队列?%d (1:是 0:否)\n",QueueEmpty(q));
//6.遍历队列
printf("队列中的元素如下:\n");
QueueTraverse(q);
//7.获取队列头元素
iStatus = getHeadElem(q, &d);
if (iStatus == OK) {
printf("队头元素是:%d\n",d);
}
//8.删除队头元素
iStatus = deQueue(&q, &d);
if (iStatus == OK) {
printf("删除了的队头元素为:%d\n",d);
}
//9.获取队头元素
iStatus = getHeadElem(q, &d);
if (iStatus == OK) {
printf("新的队头元素为:%d\n",d);
}
//10.清空队列
clearQueue(&q);
//11.销毁队列
DestoryQueue(&q);
return 0;
}
输出结果
001--顺序队列表示与操作实现
初始化队列后,队列空否?1(1:空 0:否)
入队:
0 1 2 3 4 5 6 7 8 9
队列长度为: 10
现在队列空否?0(1:空 0:否)
出队:
出队的元素:1
2 3 4 5 6 7 8 9
现在队头元素为: 2
清空队列后, 队列空否?1(1:空 0:否)
Program ended with exit code: 0
链式队列
实现
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;
typedef int QElemType; /* QElemType类型根据实际情况而定,这里假设为int */
/* 节点 */
typedef struct QNode{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
/* 定义一个链式队列 */
typedef struct {
QueuePtr front, rear;
}LinkQueue;
1.初始化
Status InitQueue(LinkQueue *Q) {
//创建一个头结点
Q->front = (QueuePtr)malloc(sizeof(QNode));
if (Q->front == NULL)
return ERROR;
//首尾指针指向头结点
Q->rear = Q->front;
//头结点的next指针指向NULL;
Q->front->next = NULL;
return OK;
}
2.销毁
Status DestoryQueue(LinkQueue *Q) {
QueuePtr p = Q->front;
QueuePtr q = p;//因为销毁后Q->rear是无用的,这里可以用Q->rear代替q,Q->front代替p。
while (p) {
q = p;
p = p->next;
free(q);
}
return OK;
}
3.置空
Status clearQueue(LinkQueue *Q) {
QueuePtr p,q;
p = Q->front;
Q->rear = Q->front;
Q->front->next = NULL;
while (p) {
q = p->next;
p->next = q->next;
free(q);
}
return OK;
}
4.判断队列是否为空
Status QueueEmpty(LinkQueue Q){
if (Q.front == Q.rear)
return TRUE;
else
return FALSE;
}
5.获取元素个数
int QueueLength(LinkQueue Q){
QueuePtr p;
p = Q.front;
int i = 0;
while (p != Q.rear) {
p = p->next;
i++;
}
return i;
}
6.入队
Status enQueue(LinkQueue *Q, QElemType e){
//创建节点
QueuePtr temp = (QueuePtr)malloc(sizeof(QNode));
if (!temp) {
return ERROR;
}
//赋值
temp->data = e;
temp->next = NULL;
//队尾的next指向新节点
Q->rear->next = temp;
//队尾指针指向新节点
Q->rear = temp;
return OK;
}
7.出队
Status deQueue(LinkQueue *Q, QElemType *e){
//判断队空
if (Q->front == Q->rear) {
return ERROR;
}
QueuePtr p;//待删除节点
p = Q->front->next;
*e = p->data;
//将原队列头结点的后继p->next 赋值给头结点后继
Q->front->next = p->next;
//若出队的数据已是队尾
if (p == Q->rear) {
//将队列置空,rear指向front
Q->rear = Q->front;
}
free(p);
return OK;
}
8.获取队头元素
Status getHeadElem(LinkQueue Q, QElemType *e) {
//判断队空
if (Q.front == Q.rear) {
return ERROR;
}
*e = Q.front->next->data;
return OK;
}
9.遍历队列
Status QueueTraverse(LinkQueue Q){
QueuePtr p;
p = Q.front->next;
while (p) {
printf("%d ",p->data);
p = p->next;
}
printf("\n");
return OK;
}
验证
int main(int argc, const char * argv[]) {
Status iStatus;
QElemType d;
LinkQueue q;
//1.初始化队列q
iStatus = InitQueue(&q);
//2. 判断是否创建成
if (iStatus) {
printf("成功地构造了一个空队列\n");
}
//3.判断队列是否为空
printf("是否为空队列?%d (1:是 0:否)\n",QueueEmpty(q));
//4.获取队列的长度
printf("队列的长度为%d\n",QueueLength(q));
//5.插入元素到队列中
enQueue(&q, -3);
enQueue(&q, 6);
enQueue(&q, 12);
printf("队列的长度为%d\n",QueueLength(q));
printf("是否为空队列?%d (1:是 0:否)\n",QueueEmpty(q));
//6.遍历队列
printf("队列中的元素如下:\n");
QueueTraverse(q);
//7.获取队列头元素
iStatus = getHeadElem(q, &d);
if (iStatus == OK) {
printf("队头元素是:%d\n",d);
}
//8.删除队头元素
iStatus = deQueue(&q, &d);
if (iStatus == OK) {
printf("删除了的队头元素为:%d\n",d);
}
//9.获取队头元素
iStatus = getHeadElem(q, &d);
if (iStatus == OK) {
printf("新的队头元素为:%d\n",d);
}
//10.清空队列
clearQueue(&q);
//11.销毁队列
DestoryQueue(&q);
return 0;
}
输出
链队列的表示与操作!
成功地构造了一个空队列
是否为空队列?1 (1:是 0:否)
队列的长度为0
队列的长度为3
是否为空队列?0 (1:是 0:否)
队列中的元素如下:
-3 6 12
队头元素是:-3
删除了的队头元素为:-3
新的队头元素为:6
Program ended with exit code: 0