约定
循环队列满:
一般情况下,队列满和队列空的情况是:
font: 队列头指针
rear: 队列尾指针
Q->font=Q->rear
约定: 牺牲一个元素控件,约定以“队列头指针在队列尾指针的下一个位置(指环状的下一个位置)上”。
约定:在入队前,测试尾指针rear在循环意义下加1后等于头指针,则认为队满。即:
- rear所指的单元始终为空
- 循环队列为空:front=rear
- 循环队列满:(rear+1)%MAX_QUEUE_SIZE = front.(对MAX_QUEUE_SIZE取余,比如6取余6就是0,就代表绕一圈后的数组索引)
- 循环队列空:font = rear.
CircleQueue.h
#ifndef _CIRCLEQUEUE_H_
#define _CIRCLEQUEUE_H_
#define OK 1
#define ERROR -1
#define MAX 100
typedef int QElementType;
typedef struct
{
QElementType *data; //指向数据缓冲区
int font; //队列头
int rear; //队列尾
}SqQueue;
int CheckQueueFull(SqQueue *Q); //判断队列是否为满
int CheckQueueEmpty(SqQueue *Q); //判断队列是否为空
int InitQueue(SqQueue *Q); //队列初始化
int EnQueue(SqQueue *Q, QElementType e); //数据入队
int DeQueue(SqQueue *Q, QElementType *e); //数据出队
void PrintQuence(SqQueue *Q); //数据处理
void testCircleQueue(void); //测试函数
#endif
Demo 1
#include "CircleQueue.h"
#include <stdio.h>
#include <stdlib.h>
//----------------------------------------------------------------------------------------------
//!brief Check Circle Queue is Full
//!
//!param Input Circle Queue ptr
//!return 1 OK
//! -1 Error
//----------------------------------------------------------------------------------------------
int CheckQueueFull(SqQueue *Q)
{
if( (Q->rear+1)%MAX == Q->font)
{
return OK;
}
else
{
return ERROR;
}
}
//----------------------------------------------------------------------------------------------
//!brief Check Circle Queue is empty
//!
//!param Input Circle Queue ptr
//!return 1 OK
//! -1 Error
//----------------------------------------------------------------------------------------------
int CheckQueueEmpty(SqQueue *Q)
{
if(Q->font == Q->rear)
{
return OK;
}
else
{
return ERROR;
}
}
//----------------------------------------------------------------------------------------------
//!brief Initial Circle Queue
//!
//!param Input Circle Queue ptr
//!return 1 OK
//!
//----------------------------------------------------------------------------------------------
int InitQueue(SqQueue *Q)
{
Q->data = (QElementType *)malloc(MAX * sizeof(QElementType)); //分配缓冲区
if (!Q->data)
{
exit(0);
}
Q->font = Q->rear = 0; //队列头和队列尾初始化
return OK;
}
//----------------------------------------------------------------------------------------------
//!brief Put a data into the Queue
//!
//!param Input Queue ptr
//!param Input Data Element
//!
//!return 1 OK
//----------------------------------------------------------------------------------------------
int EnQueue(SqQueue *Q, QElementType e)
{
if(CheckQueueFull(Q))
{
return ERROR;
}
Q->data[Q->rear] = e; //数据入队
Q->rear = (Q->rear + 1) % MAX; //重新设置队尾指针,即队尾指针增1
return OK;
}
//----------------------------------------------------------------------------------------------
//!brief Extract a data out of the Queue
//!
//!param Input Queue ptr
//!param Input Data Element ptr buffer
//!
//!return 1 OK
//----------------------------------------------------------------------------------------------
int DeQueue(SqQueue *Q, QElementType *e)
{
if (Q->font == Q->rear) //判断队列是否为空
{
return ERROR;
}
*e = Q->data[Q->font]; //获取队首元素
Q->font = (Q->font + 1) % MAX; //头指针移动
return OK;
}
//----------------------------------------------------------------------------------------------
//!brief Print out element data in the queue
//!
//!param Input Queue ptr
//!
//----------------------------------------------------------------------------------------------
void PrintQuence(SqQueue *Q)
{
int i;
i = Q->font;
while (i != Q->rear)
{
printf("%d", Q->data[i]);
i = (i + 1) % MAX;
}
printf("\n");
}
void testCircleQueue(void)
{
SqQueue Q = {0};
QElementType e=0;
int i = 5,j = 5;
InitQueue(&Q);
for(i;i>0;i--)
{
EnQueue(&Q, i);
printf("入队元素为%d\n", i);
}
PrintQuence(&Q);
for(j;j>0;j--)
{
DeQueue(&Q, &e);
printf("出队元素为%d\n",e);
}
return;
}
Demo 2
/*---------------------------------------
*CircleQueueSolution.h
*--------------------------------------*/
#ifndef _CIRCLEQUEUESOLUTION_H_
#define _CIRCLEQUEUESOLUTION_H_
#define ELEMENT_SIZE 40
#define MAX_ELEMENT_NUM 5
#define OK 1
#define ERROR -1
typedef struct MSG_TYPE
{
char msg[40]; //每个element的大小
}MSG_TYPE_ST;
typedef struct CIRCLEQUEUE
{
int font; //头部
int rear; //尾部
MSG_TYPE_ST buffer[MAX_ELEMENT_NUM]; //缓存大小
}CIRCLEQUEUE_ST;
int CQ_InitQueue(CIRCLEQUEUE_ST *Q); //初始化
int CQ_EnQueue(CIRCLEQUEUE_ST *CQ, void *element);
int CQ_DeQueue(CIRCLEQUEUE_ST *CQ, void* element);
void test_CircleQueueSolution(void);
#endif
/*---------------------------------------
*CircleQueueSolution.c
*--------------------------------------*/
#include "CircleQueueSolution.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
//circle queue object entity
static CIRCLEQUEUE_ST cq = { 0 };
//Test data source for test
static char *test_msg[] = {
"This is element 1",
"This is element 2",
"This is element 3",
"This is element 4",
"This is element 5",
};
static int CQ_IsFull(CIRCLEQUEUE_ST *CQ);
static int CQ_IsEmpty(CIRCLEQUEUE_ST *CQ);
static void PrintfCircleQueue(CIRCLEQUEUE_ST *CQ);
/*--------------------------------------------------
* Check Circle Queue is Full
* return : 1--full
* 0--not full
--------------------------------------------------*/
static int CQ_IsFull(CIRCLEQUEUE_ST *CQ)
{
if ((CQ->rear+1)%MAX_ELEMENT_NUM == CQ->font)
{
printf("Circle is full\n");
return 1;
}
else
{
return 0;
}
}
/*--------------------------------------------------
* Check Circle Queue is Empty
* return : 1--full
* 0--not full
--------------------------------------------------*/
static int CQ_IsEmpty(CIRCLEQUEUE_ST *CQ)
{
if (CQ->rear == CQ->font)
{
printf("Circle queue is empty.\n");
return 1;
}
else
{
return 0;
}
}
int CQ_InitQueue(CIRCLEQUEUE_ST *CQ)
{
CQ->font = CQ->rear = 0;
return OK;
}
/*--------------------------------------------------
* Put Element in Circle Queue
* return : 1 --OK
* -1 --ERROR
--------------------------------------------------*/
int CQ_EnQueue(CIRCLEQUEUE_ST *CQ, void *element)
{
if(CQ_IsFull(CQ)||(strlen((char *)element)>ELEMENT_SIZE)) //如果压入元素长度大于element size也返回
{
return ERROR;
}
else
{
//拷贝到缓存中
//memset(&CQ->buffer[CQ->rear],element, sizeof(element));
strncpy_s(CQ->buffer[CQ->rear].msg, ELEMENT_SIZE, element, strlen(element));
CQ->rear = (CQ->rear + 1) % MAX_ELEMENT_NUM;
return OK;
}
}
/*--------------------------------------------------
* Read Element from Circle Queue and store to element
* return : 1 --OK
* -1 --ERROR
--------------------------------------------------*/
int CQ_DeQueue(CIRCLEQUEUE_ST *CQ, void* element)
{
if (CQ_IsEmpty(CQ))
{
return ERROR;
}
else
{
//memcpy(element, &CQ->buffer[CQ->font], sizeof(MSG_TYPE_ST));
strncpy_s((char *)element, ELEMENT_SIZE, CQ->buffer[CQ->font].msg, sizeof(CQ->buffer[CQ->font].msg));
CQ->font = (CQ->font + 1) % MAX_ELEMENT_NUM;
return OK;
}
}
/*--------------------------------------------------
* Printf all Circle Queue element
* return : 1 --OK
* -1 --ERROR
--------------------------------------------------*/
static void PrintfCircleQueue(CIRCLEQUEUE_ST *CQ)
{
int i = CQ->font;
while (i != CQ->rear )
{
printf("%s\n", CQ->buffer[i].msg);
i = (i + 1) % MAX_ELEMENT_NUM;
}
}
void test_CircleQueueSolution(void)
{
char e[40] = {0};
CQ_InitQueue(&cq);
for (int i=0;i<5;i++)
{
CQ_EnQueue(&cq, test_msg[i]);
}
PrintfCircleQueue(&cq);
for (int i=0;i<3;i++)
{
CQ_DeQueue(&cq, (char *)e);
printf("%s\n", e);
memset(e, 0, sizeof(e));
}
CQ_EnQueue(&cq, "this is new msg1");
CQ_EnQueue(&cq, "this is new msg2");
CQ_EnQueue(&cq, "this is new msg3");
}
链式存储结构及实现
上述循环队列在已知队列最大长度的情况下,可以使用循环队列,但是如果入队速度大于处理速度,可能会存在因为队列满而丢失数据的情况。
此时使用链式的队列存储能从空间上解决此问题,虽然在空间上增加了开销,需要一个指针域,但是还可以接收。因此相对固定长度的队列,更加灵活。
头文件
#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_
#include "SingleLinkList.h"
//===============================================================================
//S E L F D E F I N I T I O N
//===============================================================================
#define TRUE 1
#define FALSE 0
//===============================================================================
//S T R U C T D E F I N I T I O N
//===============================================================================
typedef struct {
Node *front; //指向队列首节点的头指针
Node *rear; //指向队列尾节点的尾指针
}LinkQueue;
//===============================================================================
//F U N C T I O N D E F I N I T I O N
//===============================================================================
//-------------------------------------------------------------------------------
//初始化
//-------------------------------------------------------------------------------
void LinkQueue_InitQueue(LinkQueue *Q);
//-------------------------------------------------------------------------------
//队列空
//-------------------------------------------------------------------------------
bool LinkQueue_IsEmpty(LinkQueue *Q);
//-------------------------------------------------------------------------------
//队列满
//-------------------------------------------------------------------------------
bool LinkQueue_IsFull(LinkQueue *Q);
//-------------------------------------------------------------------------------
//元素入队
//-------------------------------------------------------------------------------
bool LinkQueue_EnQueue(LinkQueue *Q, ElemType elemData);
//-------------------------------------------------------------------------------
//元素出队
//-------------------------------------------------------------------------------
bool LinkQueue_DeQueue(LinkQueue *Q, ElemType *elemData);
//-------------------------------------------------------------------------------
//测试函数
//-------------------------------------------------------------------------------
void LinkQueue_TestQueue(void);
#endif
实现
//===============================================================================
// Link List For Queue
//===============================================================================
#include "LinkQueue.h"
//===============================================================================
//I N C L U D E F I L E
//===============================================================================
#include "LinkQueue.h"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include "assert.h"
//===============================================================================
//S T A T I C D E F I N I T I O N
//===============================================================================
static ElemType inputData[5] = {
"This is Node Data 1",
"This is Node Data 2",
"This is Node Data 3",
"This is Node Data 4",
"This is Node Data 5",
};
//===============================================================================
//S T A T I C V A R I A B L E
//===============================================================================
//===============================================================================
//G L O B A L F U N
//===============================================================================
//-------------------------------------------------------------------------------
//初始化
//-------------------------------------------------------------------------------
void LinkQueue_InitQueue(LinkQueue *Q)
{
Q->front = malloc(sizeof(Node));
if (Q->front != NULL){
Q->front->next = NULL;
}
Q->rear = malloc(sizeof(Node));
if (Q->rear != NULL) {
Q->rear->next = NULL;
}
Q->front = Q->rear;
return;
}
//-------------------------------------------------------------------------------
//队列空
//-------------------------------------------------------------------------------
bool LinkQueue_IsEmpty(LinkQueue *Q)
{
if (Q->front == Q->rear) {
return TRUE;
}
else {
return FALSE;
}
}
//-------------------------------------------------------------------------------
//队列满
//链式队列没有队列满的概念
//-------------------------------------------------------------------------------
bool LinkQueue_IsFull(LinkQueue *Q)
{
return FALSE;
}
//-------------------------------------------------------------------------------
//元素入队
//-------------------------------------------------------------------------------
bool LinkQueue_EnQueue(LinkQueue *Q, ElemType elemData)
{
/*Node procedure part*/
Node *pNode = malloc(sizeof(Node));
if (pNode== NULL){
return FALSE;
}
pNode->elem = elemData;
pNode->next = NULL;
/*Link Queue procedure part*/
Q->rear->next = pNode; //把有用元素elem新节点p赋给原队尾节点的后继
Q->rear = pNode; //把当前的p节点设置为队尾节点,rear指向pNode
return TRUE;
}
//-------------------------------------------------------------------------------
//元素出队
//-------------------------------------------------------------------------------
//!brief 出队操作,就是头节点font的后继节点出队,
// 若链表除头尾节点只剩一个元素时,则需将rear指向font
//!
//-------------------------------------------------------------------------------
bool LinkQueue_DeQueue(LinkQueue *Q, ElemType *elemData)
{
if (LinkQueue_IsEmpty(Q)){
return FALSE;
}
Node *p = NULL;
p = Q->front->next; //获取font的后继节点
strncpy_s(elemData->data, NODE_DATA_SIZE, p->elem.data, strlen(p->elem.data));//获取后继节点数据
Q->front = p->next; //头节点的后继节点修改为欲删除节点的后继
if (Q->rear == p){ //如果当前尾节点为欲删除的节点
Q->rear = Q->front; //将rear指向font
}
free(p); //释放p所指向的空间
return TRUE;
}
//-------------------------------------------------------------------------------
//测试函数
//-------------------------------------------------------------------------------
void LinkQueue_TestQueue(void)
{
LinkQueue Q;
ElemType elemData;
LinkQueue_InitQueue(&Q);
for (int i=0; i<5; i++)
{
LinkQueue_EnQueue(&Q, inputData[i]);
printf("Put \"%s\" in Queue\r\n", inputData[i].data);
}
printf("\r\n");
LinkQueue_DeQueue(&Q, &elemData);
printf("Get \"%s\" out Queue\r\n", elemData.data);
}