【数据结构--队列】

队列

一、队列的定义

​ 队列和栈一样是一种操作受限的线性表,其特殊之处在于只允许在表的头部(即队头–front)进行删除,而在表的尾部(即队尾–rear)进行插入操作,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。队列的结构体如下图所示:
在这里插入图片描述

二、链队

​ 链队是指采用链式存储结构来实现的队列,通常链队用单链表来表示,如下图所示,一个链队需要两个分别指示队头和队尾的指针才能确定。

链队的结构图

在这里插入图片描述

代码描述:

typedef int ElemType;

typedef struct QNode
{
    ElemType data;
    struct QNode* next;
} QNode, *QNodePtr;

typedef struct LinkQueue
{
    QNodePtr front,rear;
} LinkQueue, *LinkQueuePtr;

三、链队的基本操作

链队的初始化

算法步骤:

  • 生成新的结点作为头结点,队头(front)和队尾(rear)指针指向此结点
  • 头结点的指针域为空

代码如下:

/* 初始化队列 */
LinkQueuePtr InitQueue()
{
    LinkQueuePtr resultPtr = (LinkQueuePtr)malloc(sizeof(LinkQueue));
    QNodePtr header = (QNodePtr)malloc(sizeof(QNode));
    header->next = NULL;
    resultPtr->front = header;
    resultPtr->rear = header;
    return resultPtr;
}

入队

​ 由于链队是基于链表的队列,其结点为动态创建和动态删除,故不存在溢出等问题。

算法步骤:

  • 为入队元素分配结点空间,用指针tempNodePtr指向
  • 将新结点的数据域改为tempElem,指针域改为NULL
  • 将新结点插入到队尾
  • 修改队尾指针(rear)为tempNodePtr

如下图所示:
在这里插入图片描述

代码如下:

/* 入队操作 */
void EnQueue(LinkQueuePtr tempQueuePtr, ElemType tempElem)
{
    QNodePtr tempNodePtr = (QNodePtr)malloc(sizeof(QNode));
    tempNodePtr->data = tempElem;
    tempNodePtr->next = NULL;
    tempQueuePtr->rear->next = tempNodePtr;
    tempQueuePtr->rear = tempNodePtr;
}

出队

​ 链队在出队前需要判断队列是否为空,链队在出队后需要释放队头元素的所占空间

算法步骤:

  • 判断队列是否为空,若为空则返回-1
  • tempNodePtr临时保存队头元素的空间,以备释放
  • 用临时变量DeValue保存队头元素的数据域,以用于返回
  • 修改头结点的指针域,指向下一个结点
  • 判断出队元素是否为最后一个元素,若是,则将队尾指针指向头结点
  • 释放原头元素的空间并将tempNodePtr指针置为NULL

如下图所示:

在这里插入图片描述

代码如下:

/* 出队操作 */
ElemType DeQueue(LinkQueuePtr tempQueuePtr)
{
    ElemType DeValue;
    QNodePtr tempNodePtr;
    if(tempQueuePtr->front == tempQueuePtr->rear)
    {
        printf("队列为空!\n");
        return -1;
    }
    tempNodePtr = tempQueuePtr->front->next;
    DeValue = tempNodePtr->data;
    tempQueuePtr->front->next = tempNodePtr->next;
    if(tempQueuePtr->rear == tempNodePtr)
    {
        tempQueuePtr->rear = tempQueuePtr->front;
    }
    free(tempNodePtr);
    tempNodePtr = NULL;
    return DeValue;
}

打印队列

/* 打印队列 */
void OutPutQueue(LinkQueuePtr tempQueuePtr)
{
    QNodePtr tempNodePtr = tempQueuePtr->front->next;
    while (tempNodePtr)
    {
        printf("% d",tempNodePtr->data);
        tempNodePtr = tempNodePtr->next;
    }
    printf("\n");
    return ;
}

取队头元素

/* 取队头元素 */
ElemType GetHead(LinkQueuePtr tempQueuePtr)
{
    if (tempQueuePtr->front != tempQueuePtr->rear)
    {
        return tempQueuePtr->front->next->data;
    }
    printf("队列为空!\n");
    return -1;   
}

清空队列

/* 清空队列 */
void ClearQueue(LinkQueuePtr tempQueuePtr)
{
    if(tempQueuePtr->front == tempQueuePtr->rear)
    {
        printf("队列为空!\n");
        return ;
    }
    while(tempQueuePtr->front->next)
    {
        DeQueue(tempQueuePtr);
    }
}

返回队列长度

/* 返回队列长度 */
int QueueLength(LinkQueuePtr tempQueuePtr)
{
    int length = 0;
    if(tempQueuePtr->front == tempQueuePtr->rear)
    {
        printf("队列为空!\n");
        return length;
    }
    QNodePtr tempNodePtr = tempQueuePtr->front->next;
    while (tempNodePtr)
    {
        length++;
        tempNodePtr = tempNodePtr->next;
    }
    return length;
}

完整代码

#include <stdio.h>
#include <malloc.h>

typedef int ElemType;

typedef struct QNode
{
    ElemType data;
    struct QNode* next;
} QNode, *QNodePtr;

typedef struct LinkQueue
{
    QNodePtr front,rear;
} LinkQueue, *LinkQueuePtr;

/* 初始化队列 */
LinkQueuePtr InitQueue()
{
    LinkQueuePtr resultPtr = (LinkQueuePtr)malloc(sizeof(LinkQueue));
    QNodePtr header = (QNodePtr)malloc(sizeof(QNode));
    header->next = NULL;
    resultPtr->front = header;
    resultPtr->rear = header;
    return resultPtr;
}

/* 打印队列 */
void OutPutQueue(LinkQueuePtr tempQueuePtr)
{
    QNodePtr tempNodePtr = tempQueuePtr->front->next;
    while (tempNodePtr)
    {
        printf("% d",tempNodePtr->data);
        tempNodePtr = tempNodePtr->next;
    }
    printf("\n");
    return ;
}

/* 入队操作 */
void EnQueue(LinkQueuePtr tempQueuePtr, ElemType tempElem)
{
    QNodePtr tempNodePtr = (QNodePtr)malloc(sizeof(QNode));
    tempNodePtr->data = tempElem;
    tempNodePtr->next = NULL;
    tempQueuePtr->rear->next = tempNodePtr;
    tempQueuePtr->rear = tempNodePtr;
}

/* 出队操作 */
ElemType DeQueue(LinkQueuePtr tempQueuePtr)
{
    ElemType DeValue;
    QNodePtr tempNodePtr;
    if(tempQueuePtr->front == tempQueuePtr->rear)
    {
        printf("队列为空!\n");
        return -1;
    }
    tempNodePtr = tempQueuePtr->front->next;
    DeValue = tempNodePtr->data;
    tempQueuePtr->front->next = tempNodePtr->next;
    if(tempQueuePtr->rear == tempNodePtr)
    {
        tempQueuePtr->rear = tempQueuePtr->front;
    }
    free(tempNodePtr);
    tempNodePtr = NULL;
    return DeValue;
}

/* 取队头元素 */
ElemType GetHead(LinkQueuePtr tempQueuePtr)
{
    if (tempQueuePtr->front != tempQueuePtr->rear)
    {
        return tempQueuePtr->front->next->data;
    }
    printf("队列为空!\n");
    return -1;   
}

/* 清空队列 */
void ClearQueue(LinkQueuePtr tempQueuePtr)
{
    if(tempQueuePtr->front == tempQueuePtr->rear)
    {
        printf("队列为空!\n");
        return ;
    }
    while(tempQueuePtr->front->next)
    {
        DeQueue(tempQueuePtr);
    }
}

/* 返回队列长度 */
int QueueLength(LinkQueuePtr tempQueuePtr)
{
    int length = 0;
    if(tempQueuePtr->front == tempQueuePtr->rear)
    {
        printf("队列为空!\n");
        return length;
    }
    QNodePtr tempNodePtr = tempQueuePtr->front->next;
    while (tempNodePtr)
    {
        length++;
        tempNodePtr = tempNodePtr->next;
    }
    return length;
}

/* 测试 */
void test()
{
    LinkQueuePtr tempQueuePtr = InitQueue();
    printf("--------入队测试--------\n");
    EnQueue(tempQueuePtr,5);
    EnQueue(tempQueuePtr,2);
    EnQueue(tempQueuePtr,0);
    OutPutQueue(tempQueuePtr);
    printf("--------队列长度--------\n");
    printf("队列长度为%d\n",QueueLength(tempQueuePtr));
    printf("--------出队测试--------\n");
    printf("出队的元素是%d.\n",DeQueue(tempQueuePtr));
    printf("出队的元素是%d.\n",DeQueue(tempQueuePtr));
    printf("出队的元素是%d.\n",DeQueue(tempQueuePtr));
    printf("出队的元素是%d.\n",DeQueue(tempQueuePtr));
    printf("--------入队测试--------\n");
    EnQueue(tempQueuePtr,5);
    EnQueue(tempQueuePtr,2);
    EnQueue(tempQueuePtr,0);
    OutPutQueue(tempQueuePtr);
    printf("--------取队头元素--------\n");
    printf("队头元素是%d.\n",GetHead(tempQueuePtr));
    printf("--------清空队列--------\n");
    ClearQueue(tempQueuePtr);
    OutPutQueue(tempQueuePtr);
    printf("--------队列长度--------\n");
    printf("队列长度为%d\n",QueueLength(tempQueuePtr));
    printf("--------取队头元素--------\n");
    printf("队头元素是%d.\n",GetHead(tempQueuePtr));
}

int main()
{
    test();
}

运行测试

--------入队测试--------
 5 2 0
--------队列长度--------
队列长度为3
--------出队测试--------
出队的元素是5.
出队的元素是2.
出队的元素是0.
队列为空!
出队的元素是-1.
--------入队测试--------
 5 2 0
--------取队头元素--------
队头元素是5.
--------清空队列--------

--------队列长度--------
队列为空!
队列长度为0
--------取队头元素--------
队列为空!
队头元素是-1.

四、循环队列

循环队列就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用。 循环队列可以更简单防止伪溢出的发生,但队列大小是固定的。

循环队列结构图

在这里插入图片描述代码描述:

typedef int ElemType;

typedef struct CircleQueue
{
    ElemType data[MAXQSIZE];
    int front;
    int tail;
} CircleQueue,*CircleQueuePtr;

五、循环队列的基本操作

循环队列的初始化
算法步骤:

  • 为队列分配一个最大容量为MAXQSIZE的数组空间
  • 头指针(front)和尾指针(tail)置为零,表示队列为空,返回resultPtr

代码如下:

/* 初始化队列 */
CircleQueuePtr InitQueue()
{
    CircleQueuePtr resultPtr = (CircleQueuePtr)malloc(sizeof(CircleQueue));
    resultPtr->front = 0;
    resultPtr->tail = 0;
    return resultPtr;
}

入队
算法步骤:

  • 判断队列是否满,若满返回
  • 将新元素插入队尾
  • 队尾指针加1

注意:
当队列为空时,有front = tail,而当所有队列空间全占满时,也有front=tail。为了区别这两种情况,规定循环队列最多只能有MAXQSIZE - 1个队列元素,当循环队列中只剩下一个空存储单元时,队列就已经满了。因此,队列判空的条件是front = rear,队列判满的条件是front =(rear + 1) % MAXQSIZE

代码如下:

/* 入队操作 */
void EnQueue(CircleQueuePtr tempQueuePtr, ElemType tempValue)
{
    if((tempQueuePtr->tail+1) % MAXQSIZE == tempQueuePtr->front)
    {
        printf("队列已满!\n");
        return ;
    }
    tempQueuePtr->data[tempQueuePtr->tail % MAXQSIZE] = tempValue;
    tempQueuePtr->tail++;
}

出队操作
算法步骤:

  • 判断队列是否为空,为空则返回-1
  • 保存队头元素
  • 队头指针加1
/* 出队操作 */
ElemType DeQueue(CircleQueuePtr tempQueuePtr)
{
    ElemType DeValue;
    if (tempQueuePtr->front == tempQueuePtr->tail)
    {
        printf("队列为空!\n");
        return -1;
    }
    DeValue = tempQueuePtr->data[tempQueuePtr->front % MAXQSIZE];
    tempQueuePtr->front++;
    return DeValue;
}

求队列长度
对于非循环队列,尾指针和和头指针之差便是队列长度,但对于循环队列而言,差值可能为负值,因此需要将差值加上MAXQSIZE,然后对MAXQSIZE取余。
代码如下:

int QueueLength(CircleQueuePtr tempQueuePtr)
{
	return (tempQueuePtr->tail - tempQueuePtr->front + MAXQSIZE) % MAXQSIZE;
}

取循环队列的队头元素
代码如下:

/* 取队头元素 */
ElemType GetHead(CircleQueuePtr tempQueuePtr)
{
    if(tempQueuePtr->front == tempQueuePtr->tail)
    {
        printf("队列为空!\n");
        return -1;
    }
    return tempQueuePtr->data[tempQueuePtr->front];
}

完整代码

#include <stdio.h>
#include <malloc.h>
#define MAXQSIZE 5

typedef int ElemType;

typedef struct CircleQueue
{
    ElemType data[MAXQSIZE];
    int front;
    int tail;
} CircleQueue,*CircleQueuePtr;

/* 初始化队列 */
CircleQueuePtr InitQueue()
{
    CircleQueuePtr resultPtr = (CircleQueuePtr)malloc(sizeof(CircleQueue));
    resultPtr->front = 0;
    resultPtr->tail = 0;
    return resultPtr;
}

/* 入队操作 */
void EnQueue(CircleQueuePtr tempQueuePtr, ElemType tempValue)
{
    if((tempQueuePtr->tail+1) % MAXQSIZE == tempQueuePtr->front)
    {
        printf("队列已满!\n");
        return ;
    }
    tempQueuePtr->data[tempQueuePtr->tail % MAXQSIZE] = tempValue;
    tempQueuePtr->tail++;
}

/* 返回队列长度 */
int QueueLength(CircleQueuePtr tempQueuePtr)
{
	return (tempQueuePtr->tail - tempQueuePtr->front + MAXQSIZE) % MAXQSIZE;
}

/* 出队操作 */
ElemType DeQueue(CircleQueuePtr tempQueuePtr)
{
    ElemType DeValue;
    if (tempQueuePtr->front == tempQueuePtr->tail)
    {
        printf("队列为空!\n");
        return -1;
    }
    DeValue = tempQueuePtr->data[tempQueuePtr->front % MAXQSIZE];
    tempQueuePtr->front++;
    return DeValue;
}

/* 输出队列 */
void QueueTraverse(CircleQueuePtr tempQueuePtr)
{
    if (tempQueuePtr->front == tempQueuePtr->tail)
    {
        printf("队列为空!\n");
        return ;
    }
    printf("队列中的元素为:");
    for(int i = tempQueuePtr->front; i < tempQueuePtr->tail; ++i)
    {
        printf("% d",tempQueuePtr->data[i % MAXQSIZE]);
    }
    printf("\n");
}

/* 取队头元素 */
ElemType GetHead(CircleQueuePtr tempQueuePtr)
{
    if(tempQueuePtr->front == tempQueuePtr->tail)
    {
        printf("队列为空!\n");
        return -1;
    }
    return tempQueuePtr->data[tempQueuePtr->front];
}

/* 测试 */
void test()
{
    CircleQueuePtr tempQueuePtr = InitQueue();
    printf("--------入队操作--------\n");
    for(int i = 1; i < 5; ++i)
    {
        EnQueue(tempQueuePtr,i);
    }
    QueueTraverse(tempQueuePtr);
    printf("当前队列长度是%d\n",QueueLength(tempQueuePtr));
    printf("--------出队操作--------\n");
    for(int i = 0; i < 6; ++i)
    {
        printf("出队元素是%d\n",DeQueue(tempQueuePtr));
    }
    printf("当前队列长度是%d\n",QueueLength(tempQueuePtr));
    printf("--------入队操作--------\n");
    for (int i = 5; i < 9; ++i)
    {
        EnQueue(tempQueuePtr,i);
    }
    QueueTraverse(tempQueuePtr);
    printf("当前队头元素是%d\n",GetHead(tempQueuePtr));
}

int main()
{
    test();
}

运行测试

--------入队操作--------
队列中的元素为: 1 2 3 4
当前队列长度是4
--------出队操作--------
出队元素是1
出队元素是2
出队元素是3
出队元素是4
队列为空!
出队元素是-1
队列为空!
出队元素是-1
当前队列长度是0
--------入队操作--------
队列中的元素为: 5 6 7 8
当前队头元素是5

六、总结

  • 队列在日常生活中使用广泛,比如排队买 XXX、医院的挂号系统等,采用的都是队列的结构。
  • 链式队列可以实现一个无限排队的无界队列,但是极有可能导致排队过多,请求被处理的时效非常长,所以针对响应时间要求高的系统,链式队列是不适用的
  • 顺序队列是有界的,当请求入队使得队列满了后,后续请求都会被拒绝,比较适合对响应时间要求高的系统。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黎子想写好代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值