队列是线性表的一种,在操作数据元素时,和栈一样,有自己的规则:使用队列存取数据元素时,数据元素只能从表的一端进入队列,另一端出队列,如图1。

图1 队列示意图

称进入队列的一端为“队尾”;出队列的一端为“队头”。数据元素全部由队尾陆续进队列,由队头陆续出队列。

队列的先进先出原则

队列从一端存入数据,另一端调取数据的原则称为“先进先出”原则。(first in first out,简称“FIFO”)

图1中,根据队列的先进先出原则,(a1,a2,a3,…,an)中,由于 a1 最先从队尾进入队列,所以可以最先从队头出队列,对于 a2 来说,只有 a1 出队之后,a2 才能出队。

类似于日常生活中排队买票,先排队(入队列),等自己前面的人逐个买完票,逐个出队列之后,才轮到你买票。买完之后,你也出队列。先进入队列的人先买票并先出队列(不存在插队)。

队列的实现方式

队列的实现同样有两种方式:顺序存储和链式存储。

两者的区别同样在于数据元素在物理存储结构上的不同。

队列的顺序表示和实现

使用顺序存储结构表示队列时,首先申请足够大的内存空间建立一个数组,除此之外,为了满足队列从队尾存入数据元素,从队头删除数据元素,还需要定义两个指针分别作为头指针和尾指针。

当有数据元素进入队列时,将数据元素存放到队尾指针指向的位置,然后队尾指针增加 1;当删除对头元素(即使想删除的是队列中的元素,也必须从队头开始一个个的删除)时,只需要移动头指针的位置就可以了。

顺序表示是在数组中操作数据元素,由于数组本身有下标,所以队列的头指针和尾指针可以用数组下标来代替,既实现了目的,又简化了程序。

例如,将队列(1,2,3,4)依次入队,然后依次出队并输出。

代码实现:

#include <stdio.h>
int enQueue(int *a,int rear,int data){a[rear]=data;rear++;return rear;
}
void deQueue(int *a,int front,int rear){//如果 front==rear,表示队列为空while (front!=rear) {printf("%d",a[front]);front++;}
}
int main() {int a[100];int front,rear;//设置队头指针和队尾指针,当队列中没有元素时,队头和队尾指向同一块地址front=rear=0;//入队rear=enQueue(a, rear, 1);rear=enQueue(a, rear, 2);rear=enQueue(a, rear, 3);rear=enQueue(a, rear, 4);//出队deQueue(a, front, rear);return 0;
}

顺序存储存在的问题

当使用线性表的顺序表示实现队列时,由于按照先进先出的原则,队列的队尾一直不断的添加数据元素,队头不断的删除数据元素。由于数组申请的空间有限,到某一时间点,就会出现 rear 队列尾指针到了数组的最后一个存储位置,如果继续存储,由于 rear 指针无法后移,就会出错。

在数组中做删除数据元素的操作,只是移动了队头指针而没有释放所占空间。

数组真的满了吗?队头由于删除元素,front 后移, front 前边还会有可以使用的空间。所以为了充分利用这部分空间,可以考虑使用下面这种方式。

顺序存储的升级版

使用数组存取数据元素时,可以将数组申请的空间想象成首尾连接的环状空间使用。例如,在申请的内存空间大小为 5 的情况下,将数字 1-6 进队后再出队(普通方式中 6 是无法进队的):

代码实现

#include <stdio.h>
#define max 5
int enQueue(int *a,int front,int rear,int data){//循环队列中,如果尾指针和头指针重合,证明数组存放的数据已满if ((rear+1)%max==front) {printf("空间已满");return rear;}a[rear%max]=data;rear++;return rear;
}
int  deQueue(int *a,int front,int rear){//如果front==rear,表示队列为空if(front==rear) {printf("队列为空");return front;}printf("%d",a[front]);front=(front+1)%max;return front;
}
int main() {int a[max];int front,rear;//设置队头指针和队尾指针,当队列中没有元素时,队头和队尾指向同一块地址front=rear=0;//入队rear=enQueue(a,front,rear, 1);rear=enQueue(a,front,rear, 2);rear=enQueue(a,front,rear, 3);rear=enQueue(a,front,rear, 4);//出队front=deQueue(a, front, rear);rear=enQueue(a,front,rear, 5);front=deQueue(a, front, rear);rear=enQueue(a,front,rear, 6);front=deQueue(a, front, rear);front=deQueue(a, front, rear);front=deQueue(a, front, rear);front=deQueue(a, front, rear);return 0;
}

运行结果:
123456

在使用循环队列判断数组是否已满时,出现下面情况:

  • 当队列为空时,队列的头指针等于队列的尾指针
  • 当数组满员时,队列的头指针等于队列的尾指针

要将空队列和队列满的情况区分开,办法是:牺牲掉数组中的一个存储空间,判断数组满员的条件是:尾指针的下一个位置和头指针相遇,就说明数组满了。

队列的链式表示和实现(简称为“链队列”)

队列的链式存储是在链表的基础上,按照“先进先出”的原则操作数据元素。

例如,将队列(1,2,3,4)依次入队,然后再依次出队。

代码实现:

#include <stdio.h>
#include <stdlib.h>
typedef struct QNode{int data;struct QNode * next;
}QNode;
QNode * initQueue(){QNode * queue=(QNode*)malloc(sizeof(QNode));queue->next=NULL;return queue;
}
QNode* enQueue(QNode * rear,int data){QNode * enElem=(QNode*)malloc(sizeof(QNode));enElem->data=data;enElem->next=NULL;//使用尾插法向链队列中添加数据元素rear->next=enElem;rear=enElem;return rear;
}
void DeQueue(QNode * front,QNode * rear){if (front->next==NULL) {printf("队列为空");return ;}QNode * p=front->next;printf("%d",p->data);front->next=p->next;if (rear==p) {rear=front;}free(p);
}
int main() {QNode * queue,*front,*rear;queue=front=rear=initQueue();//创建头结点//向链队列中添加结点,使用尾插法添加的同时,队尾指针需要指向链表的最后一个元素rear=enQueue(rear, 1);rear=enQueue(rear, 2);rear=enQueue(rear, 3);rear=enQueue(rear, 4);//入队完成,所有数据元素开始出队列DeQueue(front, rear);DeQueue(front, rear);DeQueue(front, rear);DeQueue(front, rear);DeQueue(front, rear);return 0;
}

运行结果:
1234队列为空

在使用链队列时,最简便的方法就是链表的表头一端表示队列的队头,表的另一端表示队列的队尾,这样的设置会使程序更简单。

反过来的话,队列在增加元素的时候,要采用头插法,在删除数据元素的时候,由于要先进先出,需要删除链表最末端的结点,就需要将倒数第二个结点的next指向NULL,这个过程是需要遍历链表的。

另外需要注意的是,在删除队列中数据元素的时候,每次都需要判断队列是否为空,这就需要寻找一个判断队列为空的条件:如果头结点的指针域为NULL,说明队列为空;如果队头和队尾指针都指向头结点,说明队列为空。(二选一)

使用链队列解决问题时,要避免“野指针”的出现:

  1. 当删除最后一个数据元素时,由于一贯地认为数据元素出队列只跟队头指针有关系,会忽略队尾指针。
  2. 当链队列中只剩有一个数据元素时,队尾指针指向的就是这个数据元素,被删除后,队尾指针指向的内存空间被释放,还有可能给别的程序使用。这时候,队尾指针如果不进行重定义,就会变成“野指针”。

栈和队列:2.队列(Queue)及其C语言实现相关推荐

  1. LeetCode 232. Implement Queue using Stacks--用2个栈来实现一个队列--C++解法

    LeetCode 232. Implement Queue using Stacks–C++解法 LeetCode题解专栏:LeetCode题解 我做的所有的LeetCode的题目都放在这个专栏里,大 ...

  2. 化栈为队(两个栈来实现一个队列)

    实现一个MyQueue类,该类用两个栈来实现一个队列. 示例: MyQueue queue = new MyQueue();queue.push(1); queue.push(2); queue.pe ...

  3. Leetcode刷题 225题:用队列实现栈(基于Java和c++两种语言)

    ** Leetcode刷题 225题:用队列实现栈(基于Java和c++两种语言) ** 题目: 使用队列实现栈的下列操作: push(x) – 元素 x 入栈 pop() – 移除栈顶元素 top( ...

  4. 十、【栈和队列】队列

    队列 Queue 队列和栈一样,也属于受限线性表. 1 队列的基本概念 1.1 队列的定义 队列是只允许在表尾进行插入,表头进行删除的线性表.插入操作又称为入队,删除操作又称为出队. 队列的逻辑关系就 ...

  5. 牛客网(剑指offer) 第五题 用两个栈来实现一个队列

    //用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. //方法一:没有用到栈 $queue=array(); function mypush($node) {glo ...

  6. 【ZJOF】用来个栈来实现一个队列

    题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail 和deleteHead, 分别完成在队列尾部插入结点和在队列头部删除结点的功能 public class NList ...

  7. 栈实现队列(队列实现栈)

    <1>队列实现栈 代码实现 import java.util.LinkedList; import java.util.Queue;/*** 队列实现栈:* 方法:* 1.首先需要两个队列 ...

  8. 两个栈来实现一个队列的C++代码(某公司社会招聘笔试题)

    利用两个栈来实现一个队列, 这个问题很常见.  最关键的是要有好的思路, 至于实现, 那是很简单的事情了. 在本文中, 也想说说自己的思路, 但是, 我觉得用代码来表述思路更符合我的习惯, 也是我的菜 ...

  9. 【数据结构初阶】:栈和队列的实现(用C语言实现,附图详解和附源码)

    文章目录 栈的实现: 一.栈的概念和性质 二.栈的实现思路 三.栈的相关变量内存布局图 四.栈的初始化和销毁 五.栈的接口实现: 1.入栈 2.出栈 3.获取栈顶的数据 4.获取栈的元素个数 5.判断 ...

  10. 09 嵌入式C语言如何实现多级队列缓存(Queue、FIFO)

    C语言如何实现多级队列缓存(Queue.FIFO) 作者 将狼才鲸 日期 2022-03-20 1.各种缓存结构: 基础:指针.链表.内存.数组. 数据结构基础:表.树.图(多对多). 缓冲区/buf ...

最新文章

  1. Bzoj3550 [ONTAK2010]Vacation
  2. 关于mysql的调优
  3. Spring Cloud限流详解(附源码)
  4. python中定义变量和数组_Python中的线程和全局变量 - 数组和标准变量之间的区别?...
  5. fixed 相对于父容器定位
  6. linux debian 8.3 发布时间,Robolinux 8.3 发布下载,基于 Debian 的 Linux 发行
  7. FAILOVER详细步骤
  8. Sonarlint代码规范改造实践及一些想法
  9. Spark SQL的自定义函数UDF
  10. 计算机网络:第四章网络层课后习题及答案(精细版)
  11. 毕业设计-电子商务网站(二)
  12. 如何搭建自己的网站别人可以直接访问
  13. GEE-Scholars MODIS地表温度LST时间变化趋势
  14. DIY树莓派小车(一)树莓派4B+TB6612FNG驱动直流电机
  15. Nginx配之负载均衡、缓存、黑名单和灰度发布
  16. Feign传递请求头信息
  17. 计算机教学楼起名,“我为学校楼宇起名”征集
  18. file too small (length=0) file
  19. 最美的C语言代码参上
  20. 程序员也要懂点法律--专栏《白话法律42讲》学习总结

热门文章

  1. 铜陵高考2021年成绩查询,滁州高考成绩查询入口2021
  2. 16名本科生领衔的芯片公司 芯微电子要上市了?
  3. 清明档总票房仅1.2亿元 全国影院营业比例不足50%
  4. 百度第三季度研发费用62亿元,同比增长35%,持续高强度研发投入
  5. 双十一临近 乐视商城宣布全场包邮
  6. 收入超10亿?罗永浩:要真有这个收入 我早就还完债做智能产品去了
  7. 小鹏汽车Q2获得总营收37.6亿元,汽车交付量创季度新高
  8. 荣耀X20 SE评测:6400万高清美拍 2000元以下真香现场
  9. 华为Mate40 RS保时捷设计推8+256GB版本:起售价便宜1000元
  10. 太扎心!10亿网民:4成初中学历,月收入超5000元不足3成