单片机的 FIFO循环队列实现

转自:单片机的FIFO(先入先出)循环队列实现

 

//
// 文件:config.h
//
#ifndef __CONFIG_H 
#define __CONFIG_H
//这一段无需改动
//This segment should not be modified
#ifndef TRUE
#define TRUE  1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef unsigned char  uint8;
typedef signed   char  int8;
typedef unsigned short uint16;
typedef signed   short int16;
typedef unsigned int   uint32;
typedef signed   int   int32;
typedef float          fp32;#include "FIFOQUEUE.h"
#endif
//
// 文件:FIFOQUEUE.h
//
#ifndef _FIFOQUEUE_H
#define _FIFOQUEUE_H
#define ElemType       uint8
#define QueueSize      20 //fifo队列的大小
#define QueueFull      0  //fifo满置0
#define QueueEmpty     1  //FIFO空置1
#define QueueOperateOk 2  //队列操作完成 赋值为2
struct FifoQueue
{uint16 front;     //队列头uint16 rear;        //队列尾uint16 count;       //队列计数
    ElemType dat[QueueSize];
};
//Queue Initalize
extern void QueueInit(struct FifoQueue *Queue);
// Queue In
extern uint8 QueueIn(struct FifoQueue *Queue,ElemType sdat);
// Queue Out
extern uint8 QueueOut(struct FifoQueue *Queue,ElemType *sdat);
#endif
//
// 文件:FIFOQUEUE.C
//
#include "config.h"
//Queue Init
void QueueInit(struct FifoQueue *Queue)
{Queue->front = Queue->rear;//初始化时队列头队列首相连Queue->count = 0;   //队列计数为0
}// Queue In
uint8 QueueIn(struct FifoQueue *Queue,ElemType sdat) //数据进入队列
{if((Queue->front == Queue->rear) && (Queue->count == QueueSize)){                    // full //判断如果队列满了return QueueFull;    //返回队列满的标志}else{                    // inQueue->dat[Queue->rear] = sdat;Queue->rear = (Queue->rear + 1) % QueueSize;Queue->count = Queue->count + 1;return QueueOperateOk;}
}// Queue Out
uint8 QueueOut(struct FifoQueue *Queue,ElemType *sdat)
{if((Queue->front == Queue->rear) && (Queue->count == 0)){                    // emptyreturn QueueEmpty;}else{                    // out*sdat = Queue->dat[Queue->front];Queue->front = (Queue->front + 1) % QueueSize;Queue->count = Queue->count - 1;return QueueOperateOk;}
}
//
// 文件:Main.C
//
#include <reg52.h>
#include "config.h"
void main(void)
{struct FifoQueue MyQueue;ElemType sh;uint8 i;QueueInit(&MyQueue);while(1){for(i = 0;i < 30;i++){if(QueueIn(&MyQueue,i) == QueueFull) break;}for(i = 0;i < 30;i++){if(QueueOut(&MyQueue,&sh) == QueueEmpty) break;}}while(1);
}

 

队列是一种先进先出(first infirst out,缩写为FIFO)的线性表。它只允许在标的一端进行插入,而在另一端删除元素。这和我们日常生活中的排队是一致的,最早进入队列的元素最早离开。在队列中,允许插入的一端叫做队尾(rear),允许删除的一端则称为对头(front)(排队买票,窗口一端叫对头,末尾进队叫队尾)。

    用链表表示的队列称为链队列,如图2所示。一个链队列显然需要两个分别指向对头和队尾的指针(分别称为头指针和尾指针)才能唯一确定。这里,和线性表的单链表一样,为了操作方便起见,我们先给链队列添加一个头结点,并令头指针和尾指针均指向头结点,如图3(a)所示。链队列的操作即为单链表的插入和删除操作的特殊情况,只是尚需修改尾指针或头指针,图3(b)~(d)展示了这两种操作进行时指针变化的情况。下面给出链队列类型的模块说明。

          图3.10  

                                           图2 链队列示意图       

                    图3.11

       图3 队列运算指针变化情况 (a)空队列;(b)元素x入队;(c)元素y入队;(d)元素x出队

 

//=====ADT Queue的表示与实现===== 
//-----单链队列——队列的链式存储结构----- 
typedef struct QNode{ QElemType   data; struct QNode  *next; 
}QNode, *QueuePtr;
typedef struct{ QueuePtr front;  //对头指针 QueuePtr rear;  //队尾指针 
}LinkQueue;
//-----基本操作的函数原型说明(几个易错常考的)----- 
Status GetHead(LinkQueue Q, QElemType &e) //若队列不空,则用e返回Q的对头元素,并返回OK;否则返回ERROR 
Status EnQueue(LinkQueue &Q, QElemType e) //插入元素e为Q的新的队尾元素 
Status DeQueue(LinkQueue &Q, QElemType &e) //若队列不空,则删除Q的对头元素,用e返回其值,并返回OK; //否则返回ERROR

 

     和顺序栈相类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾的元素之外,尚需附设两个指针front和rear分别之时队列头元素和队列尾元素的位置。为了在C语言中描述方便起见,在此我们约定:初始化建空队列时,令front=rear=0,每当插入新的队列尾元素时,“尾指针增1”;每当删除队列头元素时,“头指针增1”。因此,在非空队列中,头指针始终指向队列头元素,而尾指针始终指向队列尾元素的下一个位置。如图4所示。

                 图3.12

                                             图4 头、尾指针和队列中元素之间的关系

             (a)空队列;(b)J1、J2和J3相继入队列;(c)J1和J2相继被删除;(d)J4、J5和J6相继插入队列之后J3及J4被删除

    假设当前为队列分配的最大空间为6,则当队列处于图4(d)的状态时不可再继续插入新的队尾元素,否则会因数组越界而遭致程序代码被破坏。然而此时又不宜如顺序栈那样,进行存储再分配扩大数组空间,因为队列的实际可用空间并未占满。一个较巧妙的办法是将顺序队列臆造为一个环状的空间,如图5所示,称之为循环队列。指针和队列元素之间关系不变,如图6(a)所示循环队列中,队列头元素时J3,队列尾元素是J5,之后J6、J7和J8相继插入,则队列空间均被占满,如图6(b)所示,此时Q.front=Q.rear;反之,若J3、J4和J5相继从图6(a)的队列中删除,使队列呈“空”的状态,如图6(c)所示。此时亦存在关系式Q.front=Q.rear,由此可见,只凭等式Q.front=Q.rear无法判别队列空间是“空”还是“满”。可由两种处理方法:其一是另设一个标志位以区别队列是“空”还是“满”;其二是少用一个元素空间,约定以“队列头指针在队列尾指针的下一位置(指环状的下一位置)上”作为队列呈“满”状态的标志。

                                           图3.13

 

                                                                    图5 循环队列示意图

                                 图3.14

                             图6 循环队列的头尾指针 (a)一般情况;(b)队列满时;(c)空队列;


    从上述分析可见,在C语言中不能用动态分配的一维数组来实现循环队列。如果用户的应用程序中设有循环队列,则必须为它设定一个最大队列长度;若用户无法预估所用队列的最大长度,则宜采用链队列。循环队列类型的模块说明如下:

//-----循环队列———队列的顺序存储结构----- 
#define MAXQSIZE 100   //最大队列长度 
typedef struct
{QElemType *base;  //初始化的动态非配存储空间 int front;        //头指针,若队列不空,指向队列的头元素 int rear;         //尾指针,若队列不空,指向队列尾元素的下一个位置 
}SqQueue;//-----循环队列的基本操作的算法描述----- 
Status InitQueue(SqQueue &Q)
{//构造一个空队列Q Q.base=(ElemType *)malloc(MAXQSIZE*sizeof(ElemType)); if(!Q.base) exit (OVERFLOW);  // 存储分配失败Q.front=Q.rear=0; return OK; 
}
int QueueLength(SqQueue Q){ //返回Q的元素个数,即队列的长度 return (Q.rear-Q.front+MAXQSIZE) % MAXQSIZE; 
}
Status EnQueue(SqQueue &Q, QElemType e)
{//插入元素e为Q的新的队尾元素 if((Q.rear+1) % MAXQSIZE == Q.front) return ERROR;  // 队列满Q.base[Q.rear]=e; Q.rear=(Q.rear+1) % MAXQSIZE; return OK; 
}
Status DeQueue(SqQueue &Q, QElemType &e)
{//若队列不空,则删除Q的对头元素,用e返回其值,并返回OK; //否则返回ERROR if(Q.front==Q.rear)  return ERROR; e=Q.base[Q.front]; Q.front=(Q.front+1) % MAXQSIZE; return OK; 
}

 

转载于:https://www.cnblogs.com/Danhuise/p/3915298.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/420670.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端学习(1183):指令v-cloak

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><!-- v-cloak用法 -->&…

前端学习(1184):数据绑定指令

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><!-- v-cloak用法 -->&…

前端学习(1185):数据响应式

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><!-- v-cloak用法 -->&…

前端学习(1186):双向数据绑定

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><!-- v-cloak用法 -->&…

浏览器获取正确的scrollTop值

window.pageYOffset 被所有浏览器支持除了 IE 6, IE 7, IE 8, 不关doctype的事&#xff0c; 注IE9 开始支持此属性。 window.scrollY 被Firefox, Google Chrome , Safari支持 不关doctype的事, 注IE9 不支持此属性。 在&#xff08;quirk 模式&#xff09;的时候 document.body…

拦截器,利用拦截器进行登陆权限控制

拦截器&#xff0c;登录权限控制demo1. 拦截器demo2. 登录权限控制地址&#xff1a;https://github.com/sevenyoungairye/spring-mvc-interceptor1. 拦截器demo 什么是拦截器 拦截器基于是aop思想实现的。 针对controller里面的目标方法进行拦截。 对比过滤器是过滤所有请求&…

通过CMD命令行创建和使用Android 模拟器 AVD

进行Android APP测试时&#xff0c;若手持android手机设备稀少的情况下&#xff0c;我们可以通过创建Android模拟器AVD来代替模拟android手机设备&#xff0c;本文就具体介绍如何创建和使用AVD。 1、创建AVD 每个AVD模拟一套虚拟设备来运行Android应用程序。无论…

前端学习(1188):事件绑定

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><!-- v-cloak用法 -->&…

前端学习(1189):事件基本使用

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><!-- v-cloak用法 -->&…

前端学习(1190):事件修饰符

传统方式 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><!-- v-cloak用…

mybatis --入门 单表增删改查-curd

目录1. mybatis 环境搭建2. 实体类映射文件配置&#xff08;写sql&#xff09;3. mybatis核心配置文件 &#xff08;环境配置&#xff09;4. 测试mybatis document https://mybatis.org/mybatis-3/zh/ mybatis in github https://github.com/mybatis/mybatis-3 1. mybatis 环…

lvs-dr模式原理详解和可能存在的“假负载均衡”

原文地址&#xff1a; http://blog.csdn.net/lengzijian/article/details/8089661 lvs-dr模式原理 转载注明出处&#xff1a;http://blog.csdn.net/lengzijian/article/details/8089661 先附上一张原理图&#xff1a; 为了更清晰的表述lvs-dr原理&#xff0c;我们用tcpdump工具…

把一张合成图分拆出各个小图

反编译一个程序&#xff0c;看到一张合成图&#xff0c;想分拆出里面的每个小图&#xff0c;知道了各个图的坐标大小后&#xff0c;写了一个小方法&#xff0c;希望对大家有用哈 package com.bitimage;import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStr…

mybatis TypeHandler 类型处理器

目录1. 自定义日期类型处理器2. 配置自定义日期处理器3. 新增&#xff0c;查询1. 自定义日期类型处理器 继承mybatis提供的BaseTypeHandler覆写方法&#xff0c; 来转换Java和数据库中的字段package cn.bitqian.config;import org.apache.ibatis.type.BaseTypeHandler; import…

稀疏表示

稀疏表示是近期几年信号处理领域的热点之中的一个&#xff0c;简单来说&#xff0c;它事实上是一种对原始信号的分解过程&#xff0c;该分解过程借助一个事先得到的字典&#xff08;也有人称之为过完备基&#xff0c;overcomplete basis&#xff0c;后面会介绍到&#xff09;&a…

ssm整合 durid数据源 报错java.sql.SQLException: Access denied for user ‘xxx‘@‘localhost‘

目录1、报错原因2、如何解决1、报错原因 连接数据库账号密码错误… 但我在jdbc.properties中检查账号&#xff0c; 密码都是正确的呀&#xff0c;&#x1f623; drivercom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/mybatis_study?serverTimezoneGMT usernamer…

ssm整合 报错org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):xxx

目录1. 报错原因2. 解决3. 说明1. 报错原因 使用MapperScannerConfigurer扫描对应的mapper接口&#xff0c;帮我把mapper放入spring容器中&#xff0c;但是我的mapper映射文件并没有关联到sessionFactory中。 加载mybatis核心配置文件时&#xff0c; 其中的环境&#xff0c;数…

Teradata Fastload 使用方法

第一步&#xff1a; 首先打开 teradata fastload.exe 第二步&#xff1a; 通过粘贴导入脚本 脚本&#xff1a; SESSIONS 4; ERRLIMIT 25; SET RECORD VARTEXT ",";LOGON localhost/Teradata_Education,Educate; /* localhost:IP Address; Teradata_Education:user…

Java实现邮箱发送(阿里云邮箱推送)

Java mail邮箱发送1. 邮箱信息实体类2. jar包依赖3. 发送邮箱实现绑定阿里云域名&#xff0c;创建域名账户&#xff0c;并配置解析域名账户&#xff0c;获得发送邮箱的权限&#xff0c;上限两百封&#xff0c;超出要&#xffe5;… 阿里云邮件推送控制台https://www.aliyun.co…