基础数据结构:队列

队列相对于栈来说是一个功能特性相反的结构,实现难度上与栈相当,栈与队列的学习重点都在于在实际中如何利用这两种数据结构的特点去解决问题。

队列:即只允许在队尾入数据,队头出数据(特点:先进先出FIFO(first in first out))
队列其实也类似于在现实生活中的排队,先排队的能够先出队,后排队的则在后出队

实现队列一样可以考虑使用数组/链表

数组实现时,由于队头出数据的效率比较低下(删除数据的时候,时间复杂度为O(N)),所以建议使用单链表

单链表进行出数据即是头删,入数据即是尾插 出数据时,即头删(设计合理的话效率都为O(1))

ps:只有一个结点时要注意删除完后,尾指针可能成为野指针的问题,不然下一次再插入数据时则会导致内存非法访问的错误

tip:用个结构体记录队列的头指针和尾指针,可以简化操作


了解完队列的基础特点之后我们一起来看看关于队列该如何用单链表实现(数组实现也不难,大家有兴趣的可以去尝试一下)。

首先是队列的结构

typedef int QDataType;

typedef struct QueueNode
{
    struct QueueNode *next;
    QDataType val;
}QNode;

typedef struct Queue
{
    QNode *head;
    QNode *tail;
}Queue;

队列的结构看着比栈复杂一点,不过其实只是为了简化后面的操作。

由于我们设计的是单链表实现的队列,所以需要有一个队列的结点的结构;

其次为了方便尾插数据我们可以给一个头尾指针,时刻记录着队列的首结点和尾结点
tips:我们操作时即操作这个队列的首尾结点即可

紧接着还是对整个队列进行初始化:init_queue()

void QueueInit(Queue *pq)
{
    assert(pq);
    pq->head = pq->tail = NULL;
}

 只用将我们的首尾指针连接并置空即可

初始化完后即对队列的增加数据与删除数据的操作了

增加数据:push()

void push(Queue *pq,QDataType x)
{
    assert(pq);
    QNode *newnode = (QNode*)malloc(sizeof(QNode));
    assert(newnode);
    newnode->next = NULL;
    newnode->val = x;
    if(pq->tail == NULL)
        pq->head = pq->tail = newnode;
    else 
    {
        pq->tail->next = newnode;
        pq->tail = newnode;
    }
}

删除数据:pop()

void pop(Queue *pq)
{
    assert(pq);
    assert(pq->head);

    QNode *next = pq->head->next;
    free(pq->head);
    pq->head = next;
    if(pq->head == NULL)
        pq->head = pq->tail = NULL;
}

增加数据和删除数据即本质也是对单链表的增删操作,只是增加了个头尾结点的记录而已。

如果对单链表的基础操作还不熟悉的,可以去看博主之前的单链表篇

剩下的就是对队列的一些基本访问API的实现了:返回队首的数据、返回队尾的数据、判断队列是否为空、返回队列的容量以及销毁队列等

返回队首数据:front()

QDataType front(Queue *pq)
{
    assert(pq);
    assert(pq->head);
    return pq->head->val;
}

返回队尾的数据:back()

QDataType back(Queue *pq)
{
    assert(pq);
    assert(pq->head);
    return pq->tail->val;
}

判断队列是否为空:empty()

bool empty(Queue *pq)
{
    assert(pq);
    return pq->head == NULL;
}

返回队列的容量:size()

int size(Queue *pq)
{
    int count = 0;
    QNode *cur = pq->head;
    while(cur)
    {
        count++;
        cur = cur->next;
    }
    return count;
}

销毁队列:destroy() 

void clean(Queue *pq)
{
    assert(pq);
    QNode *cur = pq->head;
    while(cur)
    {
        QNode *next = cur->next;
        free(cur);
        cur = next;
    }
    pq->head = pq->tail = NULL;
}

由于我们给了个首尾结点的记录指针,所以我们可以看到上述操作都很简单

大家可以自行实现去感受一下~

好了,看到这里,利用单链表对队列的模拟实现就结束了,如果本篇文章对你有帮助的话,那就顺手点个赞+收藏吧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

c.Coder

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

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

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

打赏作者

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

抵扣说明:

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

余额充值