初阶数据结构 队列

简介: 初阶数据结构 队列

一. 队列的基本介绍


1. 基本概念


队列是基本数据结构的一种 它符合先进先出的原则


我们来看图

ace8d77005e24a32990a2bf9e132cc6b.png



大概就是这样子的一种情况


我们将这个图形翻转180度看看


fd2e684054444490a67ce8abad1b08f4.png


我们想想看 应该用数组还是链表来实现这个结构方便一点呢


我想同学们心里现在肯定已经有了答案了


肯定不是数组


为什么呢?


以为我们如果用数组头作为队头的话 每次删数据就要往前移动很多组其他的数据


这里有同学肯定会有这样子的疑问?


不移动可不可行呢?


当然不可以 !


队列这种数据结构已经规定死了就是头出 尾进


所以说我们使用链表来实现这个数据结构


2. 代码表示


typedef int QueueNodeType;
struct QueueNode
{
  struct QueueNode * next;
  QueueNodeType val;
};
struct Queue
{
  struct QueueNode* head;
  struct QueueNode* tail;
};


仔细看


我们这里使用QueueNode来表示储存数据的一个个节点


使用Queue来表示两个指针 头和尾


二. 接口函数的实现


1. 队列初始化


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


队列初始化实际上就是将队列的两个指针置空


我们来看看效果


这里没有传二级指针进去到底能不能将一级指针置空


成功将两个指针置空了

13696fc04b7241d3b44307b7340441e7.png


这是为什么呢?


因为我们的头和尾指针实际上是储存在一个结构体里面的


当我们将结构体的地址传进去的时候 结构体指针能够访问到结构体内部的内容(这两个指针)并且可以修改它们


2. 插入数据


这里插入数据我们要考虑两种情况


第一种

4b49ac73e3b04d7c9d4f6fd2a8b89726.png





如果这里头尾指针都指向空的话


我们可以创建一个新的链表节点


然后让头尾指针都指向它


ac48b092e9fe4a2a8a49a37cfb64dbe8.png


如果说前面已经有数据了的话


这里让tail的next链接newnode


然后tail移动到后面就可以


我们来看看代码


void QueuePush(Queue* pq ,QueueNodeType x)
{
  assert(pq);
  struct QueueNode* newnode = Buynewnode();
  assert(newnode);
  // 赋值
  newnode->val = x;
  newnode->next = NULL;
  // 判断头尾指针是否为空
  if (pq->head==pq->tail==NULL)
  {
    pq->head = pq->tail = newnode;
  }
  // 赋值并链接
  else
  {
    pq->tail->next = newnode;
    pq->tail = newnode;
  }
}


看看效果怎么样

1897b495800a49a1b4764b4fc9ed8e2a.png


好像看不太清楚


我们实现一个函数打印出来试试


3. 删除数据


这里我们要注意的是


由于队列结构的特殊性


我们在打印数据的时候必须要删除数据


所以我们先写删除数据的接口函数


代码表示如下


void QueuePop(Queue* pq)
{
  //断言
  assert(pq);
  assert(pq->head);
  //每次删除一个 如果头指针指向空了 尾指针也要置空(野指针)
  // 保存下一位
  struct QueueNode* cur = pq->head->next;
  // 删除迭代
  free(pq->head);
  pq->head = cur;
  if (pq->head==NULL)
  {
    pq->tail = NULL;
  }
}

a5062f1e3bf246a9b21cd5966f08c37c.png


我们可以看到头尾指针确实置空了


我们来继续删除数据试试


66c3ff121480442f83871e1e8e3a4a4c.png


断言报错了 一切正常


4. 打印数据


一边打印 一边删除!


我们来看看效果


void QueuePrint(Queue* pq)
{
  //判断不为空
  assert(pq);
  //肯定还是用循环 打印一个删除一个 注意条件
  while (pq->head)
  {
    printf("%d-> ", pq->head->val);
    // 在删除的时候head已经迭代了 我们不用管
    QueuePop(pq);
    //在最后的时候
  }
  // 形象表示下 这里加个空指针 可以不打
  printf("NULL\n");
}


这里也有一点要注意的是


如果说打印完毕之后就不能再继续删除数据了 因为这个时候相当于数据已经被删光了


类似这样子

7fa45db490734cd3bf89cea70a88585c.png


我们再插入两个数据看看


0a97be74e9e044828942a6c45f16540b.png


相信大家经过这几次的打印应该对于队列性质的理解加深了一点了


5. 摧毁队列


void QueuePop(Queue* pq)
{
  // 断言不为空
  assert(pq);
  assert(pq->head);
  // 删除数据 释放空间 头指针向后移动
  // 这里肯定要循环删除的 注意循环的条件
  while (pq->head)
  {
    // 保存下一位
    struct QueueNode* cur = pq->head->next;
    // 删除迭代
    free(pq->head);
    pq->head = cur;
  }
  // 要注意 这里画图看看 删除掉最后一个节点的时候尾指针变空指针了 所以要对尾指针也进行赋值 
  pq->tail = NULL;
}


这里要特别注意的有一点 很容易犯错


当删掉最后一个数据的时候 想想看尾指针指向哪里?

c1b49003a01f4285ae1e7811f06ccdc5.png


tail指向了一个被释放的地址!


这怎么行


所以说在最后我们需要将tail指针置空


我们来看看效果


480ac99d6c90438490064fb59dae6f5f.png


删除完之后确实头尾都变成空了

b2bf28b6a3bb436d87e68ff512eb1434.png


如果再删除就直接报错了


6. 返回头数据


这个很简单 返回head的值就可以了


注意断言的使用


QueueNodeType QueueFront(Queue* pq)
{
  // 断言
  assert(pq);
  assert(pq->head);
  // 返回
  return pq->head->val;
}


7. 返回大小


这里定义一个整形数据size


遍历整个队列 再返回大小就可以


int QueueSize(Queue* pq)
{
  // 断言
  assert(pq);
  // 遍历 遇到NULL结束 开始就遇到NULL返回0
  int n = 0;
  struct QueueNode* cur = pq->head;
  while (cur)
  {
    cur = cur->next;
    n++;
  }
  return n;
}


代码表示如下


8. 是否为空


这个也很简单和栈差不多


这里就直接给代码了


bool QueueEmpty(Queue* pq)
{
  //断言
  assert(pq);
    // 下面其实是一个判断式 因为队列是从头出数据的 所以说判断下头指针是否为空就可以了
  return pq->head == NULL;
}


以上就是本篇博客的全部内容啦 由于博主才疏学浅 所以难免会出现纰漏


希望大佬们看到错误之后能够不吝赐教 在评论区或者私信指正 博主一定及时修正


那么大家下期再见咯

相关文章
|
1天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
31 9
|
4天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
23天前
初步认识栈和队列
初步认识栈和队列
52 10
|
24天前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
19 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
25天前
|
存储 安全 Java
【用Java学习数据结构系列】探索栈和队列的无尽秘密
【用Java学习数据结构系列】探索栈和队列的无尽秘密
28 2
|
18天前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
13 0
|
23天前
探索数据结构:队列的的实现与应用
探索数据结构:队列的的实现与应用
|
23天前
|
存储 C语言
栈和队列题目练习
栈和队列题目练习
14 0
|
25天前
|
存储 算法 Java
【用Java学习数据结构系列】用堆实现优先级队列
【用Java学习数据结构系列】用堆实现优先级队列
28 0
|
25天前
|
C语言
数据结构------栈(Stack)和队列(Queue)
数据结构------栈(Stack)和队列(Queue)
17 0