学习背景
工作两年,大多数时间都是用一些常用的代码实现一些功能,对数据结构并没有怎么使用,也没有怎么花时间去了解,只知道队列是先进先出这些基本的东西(-.-),并没有去细究其中的实现过程,直到最近在做一个项目,用到串口收发,为避免极端情况下发生发送碰撞(在极短时间内有两条发送指令一起执行,导致从机无法做到数据的有效识别,比如一些正常的指令固定每隔几分钟发一次,在这个指令准备发送的时候一个条件触发的指令也被触发了,就会一瞬间发送两条指令),受同事启发使用队列结构,其实现效果为:当有指令需要通过串口发送时,将指令标识放入队列中,主函数每隔一定时间(假定为10ms)判断队列是否为空,如果不为空则从队列中取出指令标识,判断该指令标识属于哪一个指令,然后执行该指令的发送函数。
注:下文讲解的源码来自于网络,非本人所写,如有侵权请联系作者删除,本文主要借助于源码和实验讲解队列的实现过程
写这篇博客一方面为了记录自己所学到东西,一方面为了加强理解,同时将这篇文章发布出来,希望可以得到相应的指正!
队列
队列操作
常用队列包含的操作有:创建队列、添加数据、取出数据、判断队列是否为空
本文主要介绍以数组为模型的静态方式创建一个队列的方法,既然以数组为模型,那它大致应该是这样的:创建一个指定大小的数组,该数组的长度即为队列的大小,每当向队列中存一个数,也就是给数组的指定下标赋值,然后将下标+1,该下标应该是从0开始的,所以需要一个变量记录这个操作,我们先暂时将这个变量定义为in,同时还需要一个计数器count,每存一个数,count加1,每取出一个数count减1,这个count可以用来判断队列是否为空和是否溢出,同时还需要一个变量用来记录取数据的数组下标,因为队列是先进先出,所以这个变量也是从0开始的,也就是从数组下标0开始取数据
根据以上的叙述,所以定义出一个队列的结构体变量类型,如下:
typedef struct
{
uint8_t out; //记录取数据的数组下标
uint8_t in; //记录存数据的数组下标
uint8_t count; //已存入队列中的元素个数
uint8_t queueSize;//队列大小
uint8_t elementType;//元素的大小,也就是数组元素的大小
QElementType* array;//存放你所定义的数组的指针
}
QUEUE_T;
创建队列
所谓创建队列,也就是队列的初始化,也就是对队列中各个元素的赋值,如下
#define QUEUE_SIZE 5 //队列大小
QUEUE_T MyQueue;//定义一个队列结构体变量
u8 MyQueue_pBuffer[QUEUE_SIZE];//对应队列的数组模型
u8 tx;//模拟的用于存放发送标志的变量
//函数源码
void queue_Init(QUEUE_T * pQueue, void * pBuffer, BYTE sizeOfElements, BYTE numberOfElements)
{
pQueue->out = 0;
pQueue->in = 0;
pQueue->queueSize = numberOfElements;
pQueue->count = 0;
pQueue->elementType = sizeOfElements;
pQueue->array = (BYTE*)pBuffer;
}
//初始化队列
queue_Init(&MyQueue,MyQueue_pBuffer,sizeof(MyQueue_pBuffer[0]),QUEUE_SIZE);
向队列中添加一个元素
//源码
BOOL queue_Enqueue(QUEUE_T * pQueue, void * pElement)
{
if (pQueue->count >= pQueue->queueSize)
{
return FALSE;
}
else
{
BYTE i;
BYTE* pEl = pElement;
for (i = 0; i < pQueue->elementType; i++)
{
pQueue->array[ (pQueue->in)*(pQueue->elementType) + i ] = *(pEl + i);
}
pQueue->in = (pQueue->in + 1) % pQueue->queueSize;
pQueue->count = pQueue->count + 1;
}
return TRUE;
}
//添加一个元素的调用例程
tx='1';
queue_Enqueue(&MyQueue,&tx);
从队列中取出一个元素
//源码
BOOL queue_Dequeue(QUEUE_T * pQueue, void * pElement)
{
if (pQueue->count <= 0)
{
return FALSE;
}
else
{
BYTE i;
BYTE* pEl = pElement;
for (i = 0; i < pQueue->elementType; i++)
{
*(pEl + i) = pQueue->array[(pQueue->out) * (pQueue->elementType) + i];
}
pQueue->out = (pQueue->out + 1) % pQueue->queueSize;
pQueue->count = pQueue->count - 1;
}
return TRUE;
}
//调用例程
u8 rtn;
queue_Dequeue(&MyQueue,&rtn);
我的测试实验
通过打印的内容观察分析队列原理,以下给出我的测试实验源码和实验结果,以助于理解队列,我的实验大致流程为:
创建队列(队列长度为5)
向队列中添加一个字符'1'
向队列中添加一个字符'2'
向队列中添加一个字符'3'
向队列中添加一个字符'4'
向队列中添加一个字符'5'
然后:取数据-取数据-存数据(字符‘4’)-取数据
实验源码
queue_Init(&MyQueue,MyQueue_pBuffer,sizeof(MyQueue_pBuffer[0]),QUEUE_SIZE);
my_printf("out=%d ,in=%d ,count=%d ,queueSize=%d ,elementType=%d ,array=%s\r\n",MyQueue.out,MyQueue.in,MyQueue.count,MyQueue.queueSize,MyQueue.elementType,MyQueue.array);
HAL_Delay(500);
tx='1';
my_printf("%d ",queue_Enqueue(&MyQueue,&tx));//存数据,同时打印返回值
my_printf("out=%d ,in=%d ,count=%d ,queueSize=%d ,elementType=%d ,array=%s\r\n",MyQueue.out,MyQueue.in,MyQueue.count,MyQueue.queueSize,MyQueue.elementType,MyQueue.array);
HAL_Delay(500);
tx='2';
my_printf("%d ",queue_Enqueue(&MyQueue,&tx));//存数据,同时打印返回值
my_printf("out=%d ,in=%d ,count=%d ,queueSize=%d ,elementType=%d ,array=%s\r\n",MyQueue.out,MyQueue.in,MyQueue.count,MyQueue.queueSize,MyQueue.elementType,MyQueue.array);
HAL_Delay(500);
tx='3';
my_printf("%d ",queue_Enqueue(&MyQueue,&tx));//存数据,同时打印返回值
my_printf("out=%d ,in=%d ,count=%d ,queueSize=%d ,elementType=%d ,array=%s\r\n",MyQueue.out,MyQueue.in,MyQueue.count,MyQueue.queueSize,MyQueue.elementType,MyQueue.array);
HAL_Delay(500);
tx='4';
my_printf("%d ",queue_Enqueue(&MyQueue,&tx));//存数据,同时打印返回值
my_printf("out=%d ,in=%d ,count=%d ,queueSize=%d ,elementType=%d ,array=%s\r\n",MyQueue.out,MyQueue.in,MyQueue.count,MyQueue.queueSize,MyQueue.elementType,MyQueue.array);
HAL_Delay(500);
tx='5';
my_printf("%d ",queue_Enqueue(&MyQueue,&tx));//存数据,同时打印返回值
my_printf("out=%d ,in=%d ,count=%d ,queueSize=%d ,elementType=%d ,array=%s\r\n",MyQueue.out,MyQueue.in,MyQueue.count,MyQueue.queueSize,MyQueue.elementType,MyQueue.array);
HAL_Delay(500);
my_printf("%d ",queue_Dequeue(&MyQueue,&rtn));//取数据,同时打印返回值
my_printf("rtn=%s ",&rtn);
my_printf("out=%d ,in=%d ,count=%d ,queueSize=%d ,elementType=%d ,array=%s\r\n",MyQueue.out,MyQueue.in,MyQueue.count,MyQueue.queueSize,MyQueue.elementType,MyQueue.array);
HAL_Delay(500);
my_printf("%d ",queue_Dequeue(&MyQueue,&rtn));//取数据,同时打印返回值
my_printf("rtn=%s ",&rtn);
my_printf("out=%d ,in=%d ,count=%d ,queueSize=%d ,elementType=%d ,array=%s\r\n",MyQueue.out,MyQueue.in,MyQueue.count,MyQueue.queueSize,MyQueue.elementType,MyQueue.array);
HAL_Delay(500);
tx='4';
my_printf("%d ",queue_Enqueue(&MyQueue,&tx));//存数据,同时打印返回值
my_printf("out=%d ,in=%d ,count=%d ,queueSize=%d ,elementType=%d ,array=%s\r\n",MyQueue.out,MyQueue.in,MyQueue.count,MyQueue.queueSize,MyQueue.elementType,MyQueue.array);
HAL_Delay(500);
my_printf("%d ",queue_Dequeue(&MyQueue,&rtn));//取数据,同时打印返回值
my_printf("rtn=%s ",&rtn);
my_printf("out=%d ,in=%d ,count=%d ,queueSize=%d ,elementType=%d ,array=%s\r\n",MyQueue.out,MyQueue.in,MyQueue.count,MyQueue.queueSize,MyQueue.elementType,MyQueue.array);
HAL_Delay(500);
实验结果
队列源码
最后贴出队列的源码,注:源码来自于网络,如有侵权,请联系作者删除
#include "myQueue.h" void queue_Init(QUEUE_T * pQueue, void * pBuffer, BYTE sizeOfElements, BYTE numberOfElements) { pQueue->out = 0; pQueue->in = 0; pQueue->queueSize = numberOfElements; pQueue->count = 0; pQueue->elementType = sizeOfElements; pQueue->array = (BYTE*)pBuffer; } BOOL queue_Enqueue(QUEUE_T * pQueue, void * pElement) { if (pQueue->count >= pQueue->queueSize) { return FALSE; } else { BYTE i; BYTE* pEl = pElement; for (i = 0; i < pQueue->elementType; i++) { pQueue->array[ (pQueue->in)*(pQueue->elementType) + i ] = *(pEl + i); } pQueue->in = (pQueue->in + 1) % pQueue->queueSize; pQueue->count = pQueue->count + 1; } return TRUE; } BOOL queue_Dequeue(QUEUE_T * pQueue, void * pElement) { if (pQueue->count <= 0) { return FALSE; } else { BYTE i; BYTE* pEl = pElement; for (i = 0; i < pQueue->elementType; i++) { *(pEl + i) = pQueue->array[(pQueue->out) * (pQueue->elementType) + i]; } pQueue->out = (pQueue->out + 1) % pQueue->queueSize; pQueue->count = pQueue->count - 1; } return TRUE; } uint8_t queue_GetItemCount(QUEUE_T * pQueue) { return pQueue->count; }
#ifndef _MYQUEUE_H #define _MYQUEUE_H #include<stdio.h> #include<stdlib.h> #include<stdbool.h> #include "stdint.h" #define BYTE uint8_t #define BOOL bool #define TRUE true #define FALSE false typedef uint8_t QElementType; /** * In order to use the Queue module, a variable of this type must be declared before calling * \ref ZW_util_queue_Init. */ typedef struct { uint8_t out; uint8_t in; uint8_t count; uint8_t queueSize; uint8_t elementType; QElementType* array; } QUEUE_T; /** * @brief Initializes a given queue with a given buffer. * @param[in] pQueue Pointer to the queue to initialize. * @param[in] pBuffer Pointer to a buffer to initialize the queue with. * @param[in] sizeOfElements Size of elements in the given buffer. * @param[in] numberOfElements Number of elements in the given buffer. */ void queue_Init(QUEUE_T * pQueue, void * pBuffer, BYTE sizeOfElements, BYTE numberOfElements); /** * @brief Enqueues a given element to a given queue. * @param[in] pQueue Pointer to a queue. * @param[in] pElement Pointer to an element. * @return TRUE if element was enqueued, FALSE otherwise. */ BOOL queue_Enqueue(QUEUE_T * pQueue, void * pElement); /** * @brief Dequeues a given element from a given queue. * @param[in] pQueue Pointer to a queue. * @param[out] pElement Pointer to an element. * @return TRUE if element was dequeued, FALSE otherwise. */ BOOL queue_Dequeue(QUEUE_T * pQueue, void * pElement); /** * @brief Get number of elements in queue. * @param[in] pQueue Pointer to a queue. * @return Number of queue elements. */ uint8_t queue_GetItemCount(QUEUE_T * pQueue); #endif