单片机的 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
    {                    // in
        Queue->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))
    {                    // empty
        return 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)展示了这两种操作进行时指针变化的情况。下面给出链队列类型的模块说明。

图2 链队列示意图

图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所示。

图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无法判别队列空间是“空”还是“满”。可由两种处理方法:其一是另设一个标志位以区别队列是“空”还是“满”;其二是少用一个元素空间,约定以“队列头指针在队列尾指针的下一位置(指环状的下一位置)上”作为队列呈“满”状态的标志。

图5 循环队列示意图

图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;
}

单片机的 FIFO循环队列实现

时间: 2024-08-09 03:23:21

单片机的 FIFO循环队列实现的相关文章

队列( FIFO ) 循环队列

队列( FIFO ) 数组实现 #include <stdio.h> #define N 64 int main() { int i, n, front, rear, q[2*N]; scanf("%d", &n); for(i = 0; i < n; i++) q[i] = i + 1; front = 0; rear = n; while(rear – front > 0) { printf("%d ", q[front]); f

队列(FIFO)—循环队列、队列的链式存储

1 队列的定义 队列是只允许在一端(队尾)进行插入操作,而在另一端(队头)进行删除操作的线性表. 2 队列的特点 1)先进先出是队列最大的特点,是应用中非常常见的模型,例如排队: 2)队列也属于线性表,线性表的特性队列都拥有. 3 循环队列的实现及关键点 3.1 关键点 1)队列为空的条件:队头指针等于队尾指针,即head == tial: 2)队列中保留一个元素空间,当队列满时,尾指针和头指针之间还剩一个元素空间.队列为满的条件:(tial + 1) % quenceSize == head:

09.循环队列与链队列

一.队列与循环队列 1.队列 (1)队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表.队列是一种先进先出(Fiirst In First Out)的线性表,简称FIFO.允许插入的一端称为队尾,允许删除的一端称为队头. 从队列的定义可知,队列的入队操作,其实就是在队尾追加一个元素,不需要移动任何元素,因此时间复杂度为O(1).队列的删除操作,与栈不同的是,队列元素的出列是在队头,即小标为0的位置,若要删除一个元素的话,需要移动队列的所有元素,因此事件复杂度为O(n).

循环队列的一种实现模型

前段时间在知乎上看到这样一个小题目: 用基本类型实现一队列,队列要求size是预先定义好的的.而且要求不可以使用语言自带的api,如C++的STL.普通的实现很简单,但是现在要求要尽可能的时间和空间复杂度的优化,要和语言自带的api比较时间和空间.这个队列还要支持如下的操作: constructor: 初始化队列 enqueue:入队 dequeue:出队 队列是一种基本的数据结构,在平常的应用中十分广泛,多数情况队列都是用链表实现的.但是对于本题而言,用链表实现就有这样一个问题:由于每个结点都

循环队列的实现模型

前段时间在知乎上看到这样一个小题目: 用基本类型实现一队列,队列要求size是预先定义好的的.而且要求不可以使用语言自带的api,如C++的STL.普通的实现很简单,但是现在要求要尽可能的时间和空间复杂度的优化,要和语言自带的api比较时间和空间.这个队列还要支持如下的操作: constructor: 初始化队列 enqueue:入队 dequeue:出队 队列是一种基本的数据结构,在平常的应用中十分广泛,多数情况队列都是用链表实现的.但是对于本题而言,用链表实现就有这样一个问题:由于每个结点都

数据结构基础(7) --循环队列的设计与实现

队列 队列简称队, 也是一种操作受限的线性表, 只允许在表的一端进行插入, 而在表的另一端进行删除.其特点为"先进先出(FIFO)",故又称为先进先出的线性表,简单队列如图所示: 循环队列 顺序队列有一个先天不足, 那就是空间利用率不高, 会产生"假溢出"现象,即:其实队列中还有空闲的空间以存储元素, 但我们在判断队列是否还有空间时, 队列告诉我们队列已经满了, 因此这种溢出并不是真正的溢出, 在data数组中依然存在可以放置元素的空位置, 所以说这是一种"

用顺序表实现一个循环队列

队列是一种先进先出的线性表,简称FIFO.允许插入的一端为队尾,允许出列的一端为队头. 比如一个队列q=(p1,p2,p3,p4...pn),p1就是那个队头,pn就是队尾.出列时总是从p1开始 向后,入列时总是从pn后面插入.就像敲键盘,依次敲qwr,屏幕上显示的就是qwr,先敲的先显 示. 以下代码是用顺序表实现一个循环队列 1 /** 2 * @filename queue.c 3 * @author haohaibo 4 * @data 2017/4/12 5 * @brief 用顺序表

Android之循环队列操作

队列特性:先进先出(FIFO)--先进队列的元素先出队列. 来源于我们生活中的队列(先排队的先办完事). 下面以一个简单的例子实现循环队列的操作. 1.新建Android应用程序 2.界面上添加按钮 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layo

循环队列——队列的顺序表示和实现

參考书目:<数据结构(C语言版)>,严蔚敏 怎样将<数据结构>中的知识应用到如今的工作中呢(单片机C编程.数字信号处理算法),希望在这里可以得到各位的指点.这个程序是我自己用循环队列实现了一个简单的应用模型(得益于一位童鞋的启示).这里高手如云,希望可以得到很多其它的指点啊! common.h #ifndef _COMMON_H_ #define _COMMON_H_ #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR