队列-循环队列/链队列

今天学了队列,就自己写了一下代码,队列有顺序队列和循环队列以及链队列,由于顺序队列存在“假上溢”现象,所以基本上不用,那么主要研究循环队列和链队列,循环队列是采用数组实现的,其中分别由front 和rear指示队列的头和尾,插入和删除分别只能在队尾和队首进行,这样才能实现数据先进先出的数据结构,而栈是数据现先进后出的数据结构,与队列刚好相反,所以栈只能在栈顶进行删除与插入,这样才能实现数据先进后出,回到循环队列由于当队列空或者满时,front都与rear相等,所以就存在一个空与满的判断问题,也正是存在这个问题才有下面两种实现方法,一种是用一个type_queue类型空间来换取这个问题的解决,另一个办法是用一个整数记录队列数据的个数,这样自然就能判断队列空或者满了,count=0为空,count=Max为满,下面分别给出相应代码:

//循环队列
//相应操作为(进队列)Push(),出队列pop(),取队首元素Get_top(),清空队列clear_queue(),判空Is_empty(),判满Is_full()
//第一种方式(利用空的结点来制造判断full的条件)
//#include <iostream>
#include <stdio.h>
#include <stdlib.h>
//#include <string.h>
//using namespace std;
#define Max 100 //结点个数(最大)实际存储最大数量为99(牺牲一个type_queue类型的空间)
typedef int type_queue;
typedef struct 
{
	type_queue s[Max];
	int front;
	int rear;
}Queue;

bool Is_empty(Queue *p){
	return p->front==p->rear;
}
bool Is_full(Queue *p){
	return (p->rear+1)%Max==p->front;
}
void Push(Queue *p,type_queue x){
	if(Is_full(p)){
		printf("overflow\n");
		return ;
	}
	p->s[p->rear]=x;
	p->rear=(p->rear+1)%Max;
}
type_queue Pop(Queue *p){
	if(Is_empty(p)){
		printf("belowflow\n");
		return -1;
	}
	type_queue x;
	x=p->s[p->front];
	p->front=(p->front+1)%Max;
	return x;
}
type_queue Get_top(Queue *p){
	if(Is_empty(p)){
		printf("Queue is empty\n");
		return -1;
	}
	return p->s[p->front];
}
void Init_queue(Queue *p){
	p->front=p->rear=0; //随便为0-Max-1中的一个数值即可
}
void Clear_queue(Queue *p){
	p->front=p->rear=0;//随便为0-Max-1中的一个数值即可
}


下面是另一种方法:

//第二种方法(用一个整数count记录队列中的结点数)
#include <stdio.h>
#include <stdlib.h>
#define Max 100 //实际上可以存储100各数据
typedef int type_queue;
typedef struct 
{
	type_queue s[Max];
	int front;
	int rear;
	int count;
}Queue;
bool Is_empty(Queue *p){
	return p->count==0;
}
bool Is_full(Queue *p){
	return p->count==Max;
}
void Push(Queue *p,type_queue x){
	if(Is_full(p)){
		printf("overflow\n");
		return ;
	}
	p->s[p->rear]=x;
	p->rear=(p->rear+1)%Max;
	p->count++;
}
type_queue Pop(Queue *p){
	if(Is_empty(p)){
		printf("belowflow\n");
		return -1;
	}
	type_queue x;
	x=p->s[p->front];
	p->front=(p->front+1)%Max;
	p->count--;
	return x;
}
type_queue Get_top(Queue *p){
	if(Is_empty(p)){
		printf("Queue is empty\n");
		return -1;
	}
	return p->s[p->front];
}
void Init_queue(Queue *p){
	p->front=p->rear=0;//随便为0-Max-1中的一个数值即可
	p->count=0;
}
void Clear_queue(Queue *p){
	p->front=p->rear=0;//随便为0-Max-1中的一个数值即可
	p->count=0;
}
int main()
{
	Queue q;
	Init_queue(&q);
	for(int i=0;i<100;i++)
		Push(&q,i);
	while(!Is_empty(&q))
		printf("%d ",Pop(&q));
	for(int i=0;i<100;i++)
		Push(&q,i);
	while(!Is_empty(&q))
		printf("%d ",Pop(&q));
	for(int i=0;i<100;i++)
		Push(&q,i);
	while(!Is_empty(&q))
		printf("%d ",Pop(&q));
	 Clear_queue(&q);
	 for(int i=0;i<100;i++)
		Push(&q,i);
	while(!Is_empty(&q))
		printf("%d ",Pop(&q));
	for(int i=0;i<100;i++)
		Push(&q,i);
	while(!Is_empty(&q))
		printf("%d ",Pop(&q));
	
	return 0;
}

接着是链队列的代码:

//链队列
//尾插法建链队列
//无上限,提供操作:判空Is_empty(),插入Push(),删除Pop(),清空Clear_queue(),取队首元素Get_top(),初始化队列Init_queue();
#include <stdio.h>
#include <stdlib.h>
typedef int type_queue;
typedef struct node
{
	type_queue x;
	struct node *next;
}Node;
typedef struct
{
	Node *front;
	Node *rear;
}Queue;

bool Is_empty(Queue *p){
	if(p->front==NULL && p->rear==NULL)
		return true;
	return false;
}
void Push(Queue *p,type_queue x){
	Node *s=(Node*)malloc(sizeof(Node));
	s->x=x;
	s->next=NULL;
	if(Is_empty(p)){
		p->rear=p->front=s;
		return ;
	}
	p->rear->next=s;
	p->rear=s;
}
type_queue Pop(Queue *p){
	if(Is_empty(p)){
		printf("below flow\n");
		return -1;
	}
	type_queue x=p->front->x;
	if(p->front->next==NULL){
		free(p->front);
		p->front=p->rear=NULL;
		return x;
	}
	Node *s=p->front;
	p->front=s->next;
	free(s);
	return x;
}

type_queue Get_top(Queue *p){
	if(Is_empty(p)){
		printf("the Queue is empty\n");
		return -1;
	}
	return p->front->x;
}

void Init_queue(Queue *p){
	p->front=p->rear=NULL;
}
void Clear_queue(Queue *p){
	while(!Is_empty(p))
		Pop(p);
}

int main()
{
	Queue q;
	Init_queue(&q);
	for(int i=0;i<101;i++)
		Push(&q,i);
	while(!Is_empty(&q))
		printf("%d ",Pop(&q));
	for(int i=0;i<101;i++)
		Push(&q,i);
	while(!Is_empty(&q))
		printf("%d ",Pop(&q));
	for(int i=0;i<101;i++)
		Push(&q,i);
	while(!Is_empty(&q))
		printf("%d ",Pop(&q));
	 Clear_queue(&q);
	 for(int i=0;i<101;i++)
		Push(&q,i);
	while(!Is_empty(&q))
		printf("%d ",Pop(&q));
	for(int i=0;i<101;i++)
		Push(&q,i);
	while(!Is_empty(&q))
		printf("%d ",Pop(&q));
	return 0;
}
	


/****************************************************************************** 文件名: CAN1_Queue.c 版本 : v1.0 作者 : 安诺科技 修改日期:20290608 淘宝店连接:https://shop252056293.taobao.com/ ******************************************************************************/ #include "main.h" _StCan1TxQueueMsg StCan1TxQueueMsg; _StCan1RxQueueMsg StCan1RxQueueMsg; //------------------------------------------- //Description : CAN1接收队列初始化 //Input : None //Output : None //Author : C7 20190612 //Note(s) : None //------------------------------------------- void Can1RecvQueueInit(_StCan1RxQueueMsg *StMsg) { StMsg->m_u16_size = DF_CAN1_QUEUE_LEN; //接受队列长度 StMsg->m_u16_front = 0; //头指针 StMsg->m_u16_rear = 0; //尾指针 StMsg->m_u16_counter = 0; //队内消息数 } //------------------------------------------- //Description : can1数据帧入接收队列 //Input : None //Output : None //Author : C7 20190612 //Note(s) : None //------------------------------------------- int16_t Can1RxInsQueue(can_receive_message_struct message) { //如果队列的尾指针加1等于头指针对队列长度取余 == 头指针,则队列已满 if (StCan1RxQueueMsg.m_u16_front == (StCan1RxQueueMsg.m_u16_rear + 1)%StCan1RxQueueMsg.m_u16_size) { return (E_QUEUE_FULL); } //否则将该帧消息压入队列 else { StCan1RxQueueMsg.m_queue[StCan1RxQueueMsg.m_u16_rear] = message;//写入消息 StCan1RxQueueMsg.m_u16_rear = (StCan1RxQueueMsg.m_u16_rear + 1) % StCan1RxQueueMsg.m_u16_size;//防止队列尾指针越界 return(E_QUEUE_NORMAL); } } //------------------------------------------- //Description : 删除队列的一个元素 //Input : None //Output : None //Author : C7 //Note(s) : 1、如果队列头指针和尾指针相等,则返回空 // 2、如果队列为空,则取出该元素,头指针加1 // 3、此处并没有删除队列元素,只是头指针+1 //------------------------------------------- can_receive_message_struct* Can1RxDelQueue(void) { can_receive_message_struct* pMessage; if (StCan1RxQueueMsg.m_u16_front == StCan1RxQueueMsg.m_u16_rear) { return 0; } else { pMessage = &StCan1RxQueueMsg.m_queue[StCan1RxQueueMsg.m_u16_front]; StCan1RxQueueMsg.m_u16_front = (StCan1RxQueueMsg.m_u16_front + 1)%StCan1RxQueueMsg.m_u16_size;//防止队列头指针越界 return(pMessage); } } //------------------------------------------- //Description : 表示队列的当前状态 //Input : None //Output : None //Author : C7 //Note(s) : None //------------------------------------------- int16_t Can1RxFlagQueue(void) { if (StCan1RxQueueMsg.m_u16_front == ((StCan1RxQueueMsg.m_u16_rear + 1) % StCan1RxQueueMsg.m_u16_size)) { return(E_QUEUE_FULL); } if (StCan1RxQueueMsg.m_u16_front == StCan1RxQueueMsg.m_u16_rear) { return (E_QUEUE_NULL); } return (E_QUEUE_NORMAL); } //------------------------------------------- //Description : 获得进入队列最久的元素 //Input : None //Output : None //Author : c7 //Note(s) : None //------------------------------------------- can_receive_message_struct GetCan1RxQueueMsg(void) { return StCan1RxQueueMsg.m_queue[StCan1RxQueueMsg.m_u16_front]; } //------------------------------------------- //Description : 循环发送队列初始化 //Input : None //Output : None //Author : c7 //Note(s) : None //------------------------------------------- void Can1SendQueueInit(_StCan1TxQueueMsg *StMsg) { StMsg->m_u16_size = DF_SEND_CAN1_QUEUE_LEN; StMsg->m_u16_front = 0; //头指针 StMsg->m_u16_rear = 0; //尾指针 StMsg->m_u16_counter = 0; //队内消息数 memset(StMsg->m_queue,0,sizeof(can_trasnmit_message_struct)* DF_SEND_CAN1_QUEUE_LEN); } //------------------------------------------- //Description : can数据帧入发送队列 //Input : None //Output : None //Author : C7 //Note(s) : None //------------------------------------------- int16_t Can1TxInsQueue(can_trasnmit_message_struct message) { if (StCan1TxQueueMsg.m_u16_front == (StCan1TxQueueMsg.m_u16_rear + 1)%StCan1TxQueueMsg.m_u16_size) { printf("CAN1发送队列已经满%d,%d,\r\n",StCan1TxQueueMsg.m_u16_front,StCan1TxQueueMsg.m_u16_rear); return (E_QUEUE_FULL); } else { StCan1TxQueueMsg.m_queue[StCan1TxQueueMsg.m_u16_rear] = message;//写入消息 StCan1TxQueueMsg.m_u16_rear = (StCan1TxQueueMsg.m_u16_rear + 1)%StCan1TxQueueMsg.m_u16_size;//防止队列尾指针越界 return(E_QUEUE_NORMAL); } } //------------------------------------------- //Description : 删除队列中的一个数据元素 //Input : None //Output : None //Author : C7 //Note(s) : None //------------------------------------------- can_trasnmit_message_struct* Can1TxDelQueue(void) { can_trasnmit_message_struct* pMessage; if (StCan1TxQueueMsg.m_u16_front == StCan1TxQueueMsg.m_u16_rear) { return NULL; } else { pMessage = &StCan1TxQueueMsg.m_queue[StCan1TxQueueMsg.m_u16_front]; StCan1TxQueueMsg.m_u16_front = (StCan1TxQueueMsg.m_u16_front + 1)%StCan1TxQueueMsg.m_u16_size;//防止队列头指针越界 return(pMessage); } } //------------------------------------------- //Description : 获得此时队列的标志 //Input : None //Output : None //Author : C7 //Note(s) : None //------------------------------------------- int16_t Can1TxFlagQueue(void) { if (StCan1TxQueueMsg.m_u16_front == (StCan1TxQueueMsg.m_u16_rear + 1)%StCan1TxQueueMsg.m_u16_size) { return(E_QUEUE_FULL); } if (StCan1TxQueueMsg.m_u16_front == StCan1TxQueueMsg.m_u16_rear) { return(E_QUEUE_NULL); } return (E_QUEUE_NORMAL); } //------------------------------------------- //Description : 得到最先入队列的元素 //Input : None //Output : None //Author : C7 //Note(s) : None //------------------------------------------- can_trasnmit_message_struct GetCan1TxQueueMsg(void) { return StCan1TxQueueMsg.m_queue[StCan1TxQueueMsg.m_u16_front]; } //------------------------------------------- //Description : 清空队列 //Input : None //Output : None //Author : C7 //Note(s) : None //------------------------------------------- void ClearCan1TxQueue(void) { StCan1TxQueueMsg.m_u16_front = 0; //头指针 StCan1TxQueueMsg.m_u16_rear = 0; //尾指针 StCan1TxQueueMsg.m_u16_counter = 0; //队内消息数 }
最新发布
08-15
### 3.1 CAN通信中发送和接收队列的实现机制概述 在CAN通信中,发送和接收队列通常基于队列数据结构实现,用于管理待发送的消息和接收的消息。这些队列的实现机制包括初始化、入队、出队、状态判断和清空操作,其逻辑与标准队列操作类似,但需要结合CAN通信的实时性和可靠性要求进行优化。 在嵌入式系统中,CAN通信的队列通常采用循环队列队列实现。循环队列适用于固定长度的队列管理,而队列则适用于动态扩展的场景。例如,顺序队列的初始化涉及设置队头和队尾指针,并将队列状态设置为空;而队列的初始化则需要分配内存并初始化头尾指针[^2]。 --- ### 3.2 CAN1发送队列的C代码实现分析 #### 3.2.1 发送队列的初始化 发送队列的初始化通常包括分配内存空间、设置队头和队尾指针、初始化队列容量等。以下是一个基于循环队列的CAN发送队列初始化示例: ```c #define CAN_TX_QUEUE_SIZE 16 typedef struct { CanTxMsgTypeDef buffer[CAN_TX_QUEUE_SIZE]; uint8_t head; uint8_t tail; uint8_t count; } CanTxQueue; void CAN_TxQueue_Init(CanTxQueue *queue) { queue->head = 0; queue->tail = 0; queue->count = 0; } ``` 初始化操作将队列的 `head` 和 `tail` 指针设置为初始值,并将 `count` 设置为0,表示队列为空[^2]。 #### 3.2.2 入队操作 入队操作将数据放入队列尾部,并更新 `tail` 指针和 `count`。如果队列已满,则应避免入队以防止数据丢失。 ```c int CAN_TxQueue_Enqueue(CanTxQueue *queue, CanTxMsgTypeDef *msg) { if (queue->count >= CAN_TX_QUEUE_SIZE) { return -1; // 队列已满 } queue->buffer[queue->tail] = *msg; queue->tail = (queue->tail + 1) % CAN_TX_QUEUE_SIZE; queue->count++; return 0; } ``` 该操作中需判断队列是否已满,否则可能导致数据覆盖或溢出问题[^2]。 #### 3.2.3 出队操作 出队操作从队列头部取出数据,并更新 `head` 指针和 `count`。若队列为空,则应返回错误状态。 ```c int CAN_TxQueue_Dequeue(CanTxQueue *queue, CanTxMsgTypeDef *msg) { if (queue->count == 0) { return -1; // 队列为空 } *msg = queue->buffer[queue->head]; queue->head = (queue->head + 1) % CAN_TX_QUEUE_SIZE; queue->count--; return 0; } ``` 出队操作需确保队列非空,否则可能读取无效数据。 #### 3.2.4 状态判断与清空操作 状态判断包括检查队列是否为空或满,清空操作则重置队列指针和计数器。 ```c int CAN_TxQueue_IsEmpty(CanTxQueue *queue) { return queue->count == 0; } int CAN_TxQueue_IsFull(CanTxQueue *queue) { return queue->count >= CAN_TX_QUEUE_SIZE; } void CAN_TxQueue_Clear(CanTxQueue *queue) { queue->head = 0; queue->tail = 0; queue->count = 0; } ``` 状态判断和清空操作确保队列管理的可靠性,避免因状态错误导致通信异常。 --- ### 3.3 CAN1接收队列的C代码实现分析 接收队列的实现逻辑与发送队列类似,但需考虑CAN接收中断的触发机制。接收中断将数据写入队列,主程序则从队列中读取数据进行处理。 #### 3.3.1 接收队列的初始化与操作 以下为基于队列的CAN接收队列实现示例: ```c typedef struct CanRxNode { CanRxMsgTypeDef msg; struct CanRxNode *next; } CanRxNode; typedef struct { CanRxNode *front; CanRxNode *rear; } CanRxQueue; void CAN_RxQueue_Init(CanRxQueue *queue) { queue->front = queue->rear = (CanRxNode *)malloc(sizeof(CanRxNode)); queue->front->next = NULL; } int CAN_RxQueue_Enqueue(CanRxQueue *queue, CanRxMsgTypeDef *msg) { CanRxNode *node = (CanRxNode *)malloc(sizeof(CanRxNode)); if (!node) return -1; node->msg = *msg; node->next = NULL; queue->rear->next = node; queue->rear = node; return 0; } int CAN_RxQueue_Dequeue(CanRxQueue *queue, CanRxMsgTypeDef *msg) { if (queue->front == queue->rear) { return -1; // 队列为空 } CanRxNode *tmp = queue->front->next; *msg = tmp->msg; queue->front->next = tmp->next; if (queue->rear == tmp) { queue->rear = queue->front; } free(tmp); return 0; } ``` 队列的实现允许动态扩展,适用于确定接收数据量的场景[^3]。 --- ### 3.4 潜在问题与优化建议 #### 3.4.1 数据丢失与溢出 当发送或接收队列满时,继续入队可能导致数据丢失。为避免该问题,应在入队前进行队列状态判断,并在队列满时触发中断或通知机制。 #### 3.4.2 竞争条件与同步问题 在多任务环境中,队列操作可能被多个任务或中断同时访问,导致数据一致。应使用互斥锁或中断屏蔽机制确保队列操作的原子性。 #### 3.4.3 内存泄漏 在队列实现中,未正确释放出队节点将导致内存泄漏。应确保每次出队后释放节点内存。 #### 3.4.4 实时性问题 CAN通信对实时性要求较高,若队列处理延迟过大,可能影响系统响应。可通过优化队列操作逻辑、使用中断驱动的队列填充方式提高效率。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值