首页 > 其他分享 >C语言循环队列详解

C语言循环队列详解

时间:2024-02-20 15:56:46浏览次数:25  
标签:队列 元素 C语言 MAXSIZE 详解 rear front 循环

前言

  相比于链队列,循环队列有着内存固定,效率高等特点,因而广泛应用于计算机的各个层面。本文主要介绍循环队列的概念和特点,列举一些循环队列的应用场景,以及给出用数组用C语言实现循环队列的代码。

一、什么是循环队列?

  循环队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,一般保持队尾指针(rear)大于队头指针(front)的规律,实现循环利用。

二、特点

  循环队列的特点主要包括:

  • 高效利用存储空间:循环队列通过循环使用存储空间,避免了普通队列在元素出队时需要移动大量元素的缺点,提高了队列的效率。
  • 避免假溢出:普通队列在插入元素时,如果队列已满,则需要移动大量元素才能插入新元素,这种情况下会造成假溢出。而循环队列通过循环使用存储空间,避免了这种情况的发生。
  • 适合处理用户排队等待的情况:循环队列可以高效地处理用户排队等待的情况,因为它的插入和删除操作都是在队头进行的,可以快速响应请求。
  • 需要预先分配大量存储空间:循环队列需要预先分配足够的存储空间,这可能会造成一定的空间浪费。
  • 时间复杂度:读取元素时,循环队列的时间复杂度为O(1);插入和删除元素时,循环队列的时间复杂度也为O(1)。

  总的来说,循环队列是一种高效的数据结构,它可以有效地处理排队等待的情况,避免假溢出等问题,但也需要注意预先分配存储空间的问题。

三、基本运算

  循环队列的基本运算主要包括以下几个操作:

  • 初始化:创建一个空的循环队列,并设置队列的容量和当前队列中的元素数量。
  • 入队:将一个元素添加到队列的尾部。如果队列已满,则无法添加元素。
  • 出队:从队列的头部删除一个元素。如果队列为空,则无法删除元素。
  • 判断队列是否为空:检查队列中是否有元素。
  • 判断队列是否已满:检查队列是否已达到最大容量。
  • 获取队列的元素个数:返回队列中当前的元素数量。
  • 获取队头元素:返回队列头部的元素,但不删除该元素。
  • 输出队列:将队列中所有元素打印出来。

  这些基本运算可以实现对循环队列的基本操作和管理。在实现循环队列时,需要注意队列的存储空间分配、元素的插入和删除位置以及队列为空和已满时的特殊情况处理等问题。

四、代码实现

1、初始化

循环队列初始化操作步骤如下:

1、定义一个数组空间,作为循环队列的存储空间。

2、定义两个指针,分别指向队列的头部和尾部,即front和rear。

3、初始化时,将front和rear都指向队列的头部。

代码如下(示例):

 

/*循环队列初始化*/
int init(CirclesQueue *Q)
{
  Q->front = Q->rear = 0;
  return 0;
}

2、入队

循环队列入队操作步骤如下:

1、判断队列是否已满,如果队列已满,返回100001错误信息。

2、如果队列未满,将新元素添加到rear所指向的位置。

3、将rear向后移动一位。

4、如果rear已经到达数组的末端,则将其循环移动到数组的开头。

返回成功信息。

代码如下(示例):

/*入队*/
int enqueue(CirclesQueue *Q, DataType x)
{
  if(isfull(Q))
  {
    printf("队列已满!100001\n");
    return 100001;
  }

  Q->rear = (Q->rear+1) % MAXSIZE;

  //Q->rear = (Q->rear+1) & (MAXSIZE -1 );  //实际嵌入式中经常采用mask的做法,即mask=maxSize -1;
  Q->data[Q->rear] = x;
  return 0;
}

3、出队

循环队列出队操作步骤如下:

1、判断队列是否为空,如果队列为空,返回100002错误信息。

2、如果队列非空,将front所指向的元素删除并返回。

3、将front向后移动一位。

4、如果front已经到达数组的末端,则将其循环移动到数组的开头。

返回成功信息。

代码如下(示例):

/*出队*/
int dequeue(CirclesQueue *Q, DataType *x)
{
  if(isempty(Q))
  {
    printf("队列为空!100002\n");
    return 100002;
  }
  Q->front = (Q->front+1) % MAXSIZE;

  //Q->front = (Q->front +1) & (MAXSIZE -1 );  //实际嵌入式中经常采用mask的做法,即mask=maxSize -1;
  *x = Q->data[Q->front];
  return 0;
}

4、队满

循环队列队满判断操作步骤如下:

 队列的rear指针加1之后对MAXSIZE取模结果等于front指针,表名队列已满,函数返回1,反之,队列未满,函数返回0;

 代码如下(示例):

/*队满?*/
int isfull(CirclesQueue *Q)
{
  return (Q->rear+1)%MAXSIZE == Q->front ? 1 : 0;

  //return ((Q->rear+1) & (MAXSIZE -1)) == Q->front ? 1: 0;
}

5、队空

 循环队列队空判断操作步骤如下:

 如果队列的front指针等于rear指针,队列为空,函数返回1;反之,队列不为空,函数返回0;

 代码如下(示例):

/*队空*/
int isempty(CirclesQueue *Q)
{
  return (Q->front == Q->rear) ? 1 : 0;
}

6、输出队列

循环队列中的数据元素可以通过以下步骤进行输出:

1、首先判断队列是否为空,如果为空返回100002错误信息。

2、从front开始,依次访问队列中的每个元素。

3、到达rear时,如果队列未满,则将rear向前移动一位。

4、如果rear已经到达数组的末端,则将其循环移动到数组的开头。

5、继续从front开始遍历,直到访问完所有元素。

代码如下(示例):

/*输出队列*/
void print(CirclesQueue *Q)
{
  int i;
  if(isempty(Q))
  {
    printf("队列为空!100002\n");
    return 100002;
  }

  i=(Q->front)%MAXSIZE;

  //i=(Q->front) & (MAXSIZE - 1);// 嵌入式中常采用该种写法
  do{
    printf("%d ",Q->data[(i+1 %MAXSIZE)]);

    //printf("%d", Q->data[(i+1) & (MAXSIZE - 1)]);// 嵌入式中常采用该种写法
    i=(i+1)%MAXSIZE;
  } while(i!=Q->rear);
}

7、队列大小

循环队列获取队首元素的方法如下:

循环队列的大小可以通过rear指针和front指针之间的距离来得到。为了确保在计算队列长度时不会超出数组的边界,可以用rear指针减front头指针加上MAXSIZE再对MAXSIZE取模就可已得到队列大小。

代码如下(示例):

/*获取队列中元素个数*/

int getSize(CirclesQueue *Q)
{
  return (Q->rear-Q->front+MAXSIZE)%MAXSIZE;

  // return (Q->rear + MAXSIZE - Q->front) & (MAXSIZE -1);// 嵌入式中常采用该种写法
}

8、获取队首元素

循环队列获取队首元素的方法如下:

1、首先判断队列是否为空,如果则返回100002错误信息。

2、可以通过front加1后对MAXSIZE取模获取队首元素的位置。

代码如下(示例):

/*获取队首元素*/
int getFront(CirclesQueue *Q,DataType *x)
{
  if(isempty(Q))
  {
    printf("队列为空!100002\n");
    return 100002;
  }
  int i;
  i = (Q->front+1) % MAXSIZE;

  // i = (Q->front+1) & (MAXSIZE - 1);
  *x = Q->data[i];
  return 0;
}

五、队列应用场景

  队列的应用场景主要包括:

  • 异步处理:在这种场景中,可以使用消息队列实现异步处理任务。例如,在用户注册后,可以通过消息队列发送注册邮件和短信,而不需要等待这两个任务完成后再返回给用户。这种方式可以提高处理效率。
  • 应用解耦:业务系统中,一些非核心的或非关键的部分可以使用消息队列来实现与应用解耦,从而降低系统的复杂性。例如,电商网站在促销期间抢购订单时,可以将抢到的商品订单信息放入消息队列,然后由出库、发货等后续系统从队列里读取任务信息并执行。
  • 流量削锋和消息通讯:在流量洪流突然来袭时,可以通过队列服务堆积缓存订单等信息,在下游系统有能力处理消息的时候再处理,避免下游订阅系统因突发流量崩溃。此外,消息队列还提供亿级消息堆积能力,3天的保留时长,消息消费系统可以错峰进行消息处理。
  • 最终一致性:在交易或支付系统中,不同的子系统/模块的状态需要最终保持一致,或都成功或都失败。子系统/模块之间传递的数据不能丢失,需要有可靠消息传递,能保证业务的连续性。分布式消息服务可以用于子系统/模块间的高可靠数据传递,实现两者之间的事务最终一致,降低实现难度和成本。

  总之,消息队列在异步处理、应用解耦、流量削锋和消息通讯、最终一致性等场景中具有广泛的应用价值。

六、总结

  循环队列是一种先进先出(FIFO)的数据结构,它可以在固定大小的数组中实现队列的操作。相比于普通队列,循环队列的优点在于其队尾指针可以循环回到数组的开头,使得队列的操作更加高效。

  循环队列的应用场景非常广泛,例如在操作系统中实现任务调度、在通信协议中实现数据包的存储和处理、在线程池中管理线程的执行等。循环队列的优点包括高效的插入和删除操作、空间利用率高、可以动态地调整队列大小等。

标签:队列,元素,C语言,MAXSIZE,详解,rear,front,循环
From: https://www.cnblogs.com/FireLife-Cheng/p/18023293

相关文章

  • Unity基于AssetBundle资源管理流程详解
    在Unity游戏开发中,资源管理是一个非常重要的环节。随着游戏的发展,资源会变得越来越庞大,因此需要一种高效的资源管理方式来减少内存占用和加快加载速度。AssetBundle是Unity提供的一种资源打包和加载方式,可以将资源打包成一个独立的文件,然后在运行时进行加载和卸载。本文将详细介绍......
  • Unity MVC开发模式与开发流程详解
    在Unity游戏开发中,采用MVC(Model-View-Controller)模式是一种非常常见的设计模式。MVC模式将应用程序分为三个部分:模型(Model)、视图(View)和控制器(Controller)。这种模式可以有效地分离应用程序的逻辑和用户界面,使得代码更易于维护和扩展。本文将详细介绍Unity中的MVC开发模式及其开发流......
  • 2024-02-19-物联网C语言(9-链表)
    9.链表9.1概念假如:做一个班级信息管理系统,统计班级学生的信息而我们事先不知道班级人数,或者知道人数,但是中间人员可能发生变化:比如有新同学加入,有同学请假,又或者我们需要统计班级的平均成绩等等目标:要做一个类似QQ、飞秋类似的通信软件,其中有一个功能,类似用户上下线检测、......
  • placement服务详解
    一:简介1:作用监控云中所有硬件资源使用情况的组件比如,虚拟机都是占用了一部分物理机的资源,cpu,内存,磁盘等,有这个监控功能就能知道计算机的资源情况,哪些是空闲的为什么需要这个组件:就是openstack云计算平台需要知道在云中所有计算机集群中还有哪些计算机拥有足够的硬件资源能够......
  • 多线程系列(三) -synchronized 关键字使用详解
    一、简介在之前的线程系列文章中,我们介绍了线程创建的几种方式以及常用的方法介绍。今天我们接着聊聊多线程线程安全的问题,以及解决办法。实际上,在多线程环境中,难免会出现多个线程对一个对象的实例变量进行同时访问和操作,如果编程处理不当,会产生脏读现象。二、线程安全问题介......
  • 第十七节:动态规划详解(斐波那契数列、)
    一.        二.        三.         !作       者:Yaopengfei(姚鹏飞)博客地址:http://www.cnblogs.com/yaopengfei/声     明1:如有错误,欢迎讨论,请勿谩骂^_^。声     明2:原创博客请在转载......
  • 云电脑Win7系统安装报错详解:问题与解决方案
    本文分享自天翼云开发者社区《云电脑Win7系统安装报错详解:问题与解决方案》,作者:每日知识小分享随着云计算技术的快速发展,越来越多的人开始使用云电脑。然而,在为云电脑安装Win7系统时,一些用户可能会遇到各种安装错误。本文将详细介绍在云电脑Win7系统安装过程中可能出现的报错,分析......
  • 【FLINK学习笔记】 FLINK WINDOW(窗口)详解
    【FLINK学习笔记】FLINKWINDOW(窗口)详解一、Window分类GlobalWindow和和KeyedWindow在运用窗口计算时,Flink根据上游数据集是否为KeyedStream类型,对应的Windows也会有所不同。KeyedWindow:上游数据集如果是KeyedStream类型,则调用DataStreamAPI的window()方......
  • 最新Burp Suite插件详解
    Burp Suite中的插件BurpSuite中存在多个插件,通过这些插件可以更方便地进行安全测试。插件可以在“BAppStore”(“Extender”→“BAppStore”)中安装,如图3-46所示。   图3-46   下面列举一些常见的BurpSuite插件。 1.Active Scan++ActiveScan++在BurpSuite......
  • Flink详解系列之六--窗口机制
    Flink详解系列之六--窗口机制窗口是flink处理无限流的核心,窗口将流拆分为有限大小的“桶”,我们可以在这些桶上进行计算。1、KeyedvsNon-KeyedWindows根据上游数据是否为KeyedStream类型(是否将数据按照某个指定的Key进行分区),将窗口划分为KeyedWindow和Non-KeyedWindow......