单片机的 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用法 -->&…

mvc自定义日期转换器

1. 配置编码过滤器 1&#xff0c; web.xml中设置配置spring mvc提供的编码过滤器&#xff0c;解决get/post提交过来的数据乱码问题 <!--配置编码过滤器--><filter><filter-name>characterEncodingFilter</filter-name><filter-class>org.spring…

link引入和@import的区别

本质上, 这两种方式都是加载CSS文件, 但还是存在着细微的差别 import 机制不同于link&#xff0c;link是加载页面前css加载完毕&#xff0c;import 是先读取文件再加载import是css2.0里的 ie5以上不支持用js控制dom时改变样式&#xff0c;只能用link&#xff0c;import不是dom…

重新理解javascript回调函数

把函数作为参数传入到另一个函数中。这个函数就是所谓的回调函数 经常遇到这样一种情况&#xff0c;某个项目的A层和B层是由不同的人员协同完成.A层负责功能funA,B层负责funcB。当B层要用到某个模块的数据,于是他对A层人员说,我需要你们提供满足某种需求的数据,你给我提供一个接…

前端学习(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用法 -->&…

struts2文件上传,下载

目录1. 页面表单2. 上传下载实现1. 页面表单 <HTML><HEAD><TITLE>上传下载图片</TITLE><meta http-equiv"Content-Type" content"text/html; charsetGBK"></head><body><form enctype"multipart/form-…

各个浏览器以及内核

//IE :trident 简写:-ms- //Firefox :Gecko 简写:-moz-//Google chrome:webkit/blink 简写:-webkit-//Sefari:webkit 简写:-webkit-//opera:presto 简写:-o-

Windows安装Python包下载工具pip遇到的问题

到Python的官网下载get-pip.py文件&#xff0c;然后按照说明进行安装。 在安装过程中&#xff0c;我遇到以下问题&#xff1a; cmd的codepage引起的编码错误&#xff0c;提示65001编码错误&#xff0c;通过chcp 936切换到默认的代码页可解决此问题。其次是权限的问题&#xff0…

前端学习(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用法 -->&…

Tomcat7.0+的JNDI问题

上次搭建springspringmvcmybatis框架时用的第三方连接池jar包&#xff0c;但是部署到tomcat中后访问没有问题&#xff0c;但是启动时报了个JNDI的错&#xff0c;我没用JNDI你给我报什么&#xff0c;fuck&#xff01;把错误贴到百度上搜索没搜到&#xff0c;更fuck&#xff0c;没…

spring mvc 实现单文件 || 多文件上传

文件上传1. pom依赖&#xff08;jar包&#xff09;2. 文件上传解析器配置3. 上传实现4. 下载||文件展示实现&#xff08;io流的实现&#xff09;项目下载地址https://github.com/sevenyoungairye/File-Upload1. pom依赖&#xff08;jar包&#xff09; <!-- common upload fi…

前端学习(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里面的目标方法进行拦截。 对比过滤器是过滤所有请求&…

vue的watch监听

Vue.js 有一个方法 watch&#xff0c;它可以用来监测Vue实例上的数据变动。 如果对应一个对象&#xff0c;键是观察表达式&#xff0c;值是对应回调&#xff0c;值也可以是方法名&#xff0c;或者是对象&#xff0c;包含选项。 <template><div><el-input v-mo…

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

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

docker安装-环境阿里OS7安装

docker安装-环境阿里OS7安装 官网地址 第一步 curl -fsSL https://get.docker.com -o get-docker.sh第二步 sh get-docker.sh第三步-- 开启docker systemctl start docker第四步–查看docker版本 docker version欧克

mvc框架异常处理机制

目录1.mvc 框架提供的SimpleMappingExceptionResolver2. 继承HandlerExceptionResolver类&#xff0c;根据controller抛出的异常&#xff0c;进行对应的业务操作项目地址https://github.com/sevenyoungairye/spring-mvc-exception1.mvc 框架提供的SimpleMappingExceptionResolv…

前端学习(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用法 -->&…