C语言之循环队列与队列的链式存储结构

约定

循环队列满:

一般情况下,队列满和队列空的情况是:
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);

}

输出

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值