【数据结构】队列(顺序存储结构、链式存储结构) C语言例程

本文介绍了队列的基本概念和特点,重点探讨了队列的顺序存储结构,包括其不足之处及如何改进为循环队列,并提供了C语言实现循环队列的代码示例。此外,还简述了队列的链式存储结构及其操作,如入队和出队。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



队列(queue)是只允许在一段进行插入操作,而在另一端进行删除操作的线性表。具有先进先出的特点,允许插入的一段称为队尾,允许删除的一端称为队头。

队列

队列的顺序存储结构

顺序存储的不足

首先建立一个长度为n的数组,队列中存储的数据不大于n。在队列中添加一个元素入下图所示

入队列

在队尾后追加一个元素,即可。那么删除一个元素呢?在队头出删除一个元素后,前面会空出一个位置,因此将后面的元素均向前移动一位。

出队列

但是这样会随着队列中的数据越来越多,而使得每次删除一个元素,都需要移动全部元素,对性能影响比较大。

所以不妨可以移动队头,这样操作就简单的多。

出队列_1

为了避免当队列中没有元素和只有一个元素时,队头和队尾重合,不妨将队尾向后移动一位,指向最后一个元素的下一位空位置。

这样的存储方式也有很多问题,第一,当数组第5位添加一个元素时,队尾应该指向哪里?第二,随着队列的元素删除,数组前面的位置出现大量的空位置,因此引入循环队列,将数组的头和尾连接起来,这样就可以很好的处理上述问题。


循环队列

需要注意的是,因为循环队列在队列满员时,队头和队尾是重合的,这显然和空队列时是混淆的,因此我们要保留一个空闲位置,认为此时队列已满。

满队列

现在实现循环队列的代码。

顺序存储结构如下:

#define MAXSIZE (20)
typedef struct
{
    int data[MAXSIZE]; //数组,类型为int,可自行定义
    int front; //队头-数组的下标
    int rear; //队尾
}sqQueue;

队列的初始化代码:

/* 初始化为空队列 */
void InitQueue(sqQueue *Q)
{
    Q->front = 0;
    Q->rear = 0;
}

计算队列的长度:

思路:

(1)当队尾rear大于等于队头front时,队列的长度等于rear - front
(2)当队尾rear小于队头front时,队列的长度等于rear + MAXSIZE - front

/* 返回队列的长度 */
int GetQueueLength(sqQueue Q)
{
    return (MAXSIZE + Q.rear - Q.front) % MAXSIZE;
}

入队操作如下:

/*********************************************\
*function: 入队列,将一个数据放入队列中
*input: int data - 数据
*output: sqQueue *Q - 队列指针
*return: bool - 布尔遍历(TRUE,FALSE)
\*********************************************/
bool PutQueue(sqQueue *Q, int data)
{
    assert(Q != NULL); //检查Q是否为空指针
    if ((Q->rear + 1) % MAXSIZE == Q->front) //是否满员
    {
        return FALSE;
    }

    Q->data[Q->rear] = data; //存入数据

    Q->rear = (Q->rear + 1) % MAXSIZE; //队尾rear向后移一位

    return TRUE;
}

出队操作如下:

/*********************************************\
*function: 出队列,从队列中取出一个数据
*input: sqQueue *Q - 队列指针
*output: int data - 数据
*return: bool - 布尔遍历(TRUE,FALSE)
\*********************************************/
bool GetQueue(sqQueue *Q, int *data)
{
    assert(Q != NULL);
    if (Q->rear == Q->front) //是否为空队列
    {
        return FALSE;
    }

    *data = Q->data[Q->front]; //将队头数据赋给*data
    Q->front = (Q->front + 1) % MAXSIZE; //队头front向后移一位

    return TRUE;
}


队列的链式存储结构

队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而异,我们把他们简称为链队列。我们将队头指向链表的头结点,队尾指向链表的终端结点。

链表操作可以参考线性表总结(顺序存储、链表)

存储结构图如下:

链式队列

当队列为空时,frontrear均指向头结点。

入队

入队操作如下:

bool PutQueue_Link(LinkQueue *Q, int data)
{
    QNode *s = (QNode *)malloc(sizeof(QNode));
    if (NULL == s)
    {
        return FALSE;
    }
    s->data =  data; //新结点赋值
    s->next = NULL;

    Q->rear->next = s; //当前队列尾结点的next指向新结点
    Q->rear = s; //将新结点作为队列的尾结点

    return TRUE;
}

出队

出队操作如下:

出队操作

bool GetQueue_Link(LinkQueue *Q, int *data)
{
    QNode *p;
    if (Q->front == Q->front) //空队列
    {
        return FALSE;
    }

    p = Q->front->next;
    *data = p->data; //队头数据赋给*data
    Q->front->next = p->next;

    if (Q->rear == p) //如果原队列只有一个元素,则将队尾指针指向头结点
    {
        Q->rear = Q->front;
    }

    free(p); //删除结点
    return TRUE;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值