嵌入式0基础开始学习 Ⅱ 数据结构(4)队列

1 队列概念

队列是一种 先进先出 Fisrt In First Out, FIFO ) 的线性表
它只允许在表的一端进行插入数据,在表的另外一端删除数据
允许插入数据的那一端称为队尾 (rear / tail)
允许删除数据的那一端称为队头 (front / head)

2 队列的存储结构

2.1 顺序结构
队列的顺序结构也称之为顺序队列
它是一组地址连续的存储单元来存放队列中的元素
由于队列中的元素插入和删除限制在表的两端进行的,因此,设置队头 指针 和 队尾 指针 ,分别指出
当前队列的队头和队尾的位置
基本操作:
初始化一个空的队列, queue_init();
入队 push / enqueue
出队 pop / dequeue
获取队头元素的值 get_front()
判断队列是否为空
清空队列,销毁队列
2.2 循环队列
在顺序结构,元素入队时只修改队尾 " 指针 " , 元素出队时,只修改队头 " 指针 "
由于顺序队列的存储空间是提前设定,所以队尾 指针 会有一个上限值, 当队尾 指针 到达这个上限
值,就只能进行出队操作,不能再通过队尾 " 指针 " 来实现新元素的入队操作。
一般将顺序队列设想成一个 环状结构 ( 通过整数取余运算实现 ) , 则可维持入队,出队的简单性 , 我们称之
循环队列
设循环队列 Q 的容量为 MAXSIZE, 初始时队列为空, 且 Q.rear Q.front 都是 0 ,如下图 a
元素入队时,修改队尾指针 Q.rear = (Q.rear + 1) % MAXSIZE , 如下图 b
元素出队时,修改队头指针 Q.front = (Q.front + 1) % MAXSIZE , 如下图 c
不断的出队,当出队操作导致队列为空的时候,有 Q.front == Q.rear , 如图 d
如果不断的入队,导致队满了,则有 Q.front == Q.rear, 如下图 e 在队列空和队列满的情况下,循环队列的队头 指针 和队尾 " 指针 " 的位置是相同的,此时,我们无法根据
Q.rear Q.front 来判断队列的状态
为了区分队空还是队满,常用以下方法进行处理 :
牺牲一个存储单元,约定好 :
队列的队尾 指针 所在位置的下一个位置是队头 " 指针 " 时,此时,认为队列已满。如下图 f
还可以通过记录队列中的元素个数来判断队列是否已满
typedef int ElemType;
#define MAXSIZE 10
typedef struct Seqqueue
{
ElemType data[MAXSIZE]; //数据域
int front; //队头"指针"
int rear; //队尾"指针"
int num; //队列中的元素个数
}Seqqueue;
if(num == 0) //队列为空
if(num == MAXSIZE) //队列已满
2.3 链式队列
相当于一端进行插入,另一端进行删除的链表,就是一个队列 ( 链式队列 )
链式队列的创建
入队 ( 尾插 )
出队 ( 删除第一个元素 )
获取队头元素的数据
判断队列是否为空
销毁队列
..........

3. 后缀表达式

中缀表达式 :
: 1 + 2 * 3
100 + 200 * 3 / 2
后缀表达式 :
: 1 2 3 * +
100 200 3 * 2 / +
3.1 中缀转后缀的一般思路
遍历中缀表达式
1 、如果遇到数字,则直接入队
2 、如果遇到的是运算符,则运算符入栈
入栈规则:
a. 如果栈为空,则直接入栈
b. 如果栈不为空,则需要比较入栈的运算符与栈顶元素的优先级
如果待入栈的运算符的优先级比栈顶元素优先级高,则直接入栈
否则,需要把栈顶元素弹出,并进行入队,继续比较待入栈元素与新的栈顶元素的优先级
重复以上过程
3 、当遍历完中缀表达式之后,依次把栈中的运算符弹出,入队。
当栈空后,队列中保存的就是所谓的 后缀表达式。
3.2 后缀表达式的计算
1 、遍历后缀表达式队列,获取并移除队头元素
2 、对队头元素做判断
a. 如果队头元素是数字,则直接入栈
b. 如果是运算符,则从栈中依次弹出两个元素,分别作为运算符的右操作数 ( 先弹出的 ) 和左操作数 (
弹出的 ) ,用当前运算符进行计算,最后把计算的结果进行入栈
重复上面的过程,直到队列为空,最后的结果存储在栈中
计算过程:

顺序队列代码:

seqqueue.c

#include "seqqueue.h"


/*
	功能: 创建一个空的队列
	返回值:
		队列的地址
*/
Seqqueue* queue_init()
{
	Seqqueue* queue = malloc(sizeof(Seqqueue));

	queue->front = 0;
	queue->rear = 0;	//一开始,队头和队尾在同一位置,表示队列为空

	return queue;
}

/*
	功能: 入队
	参数:
		queue: 队列的地址
		value: 需要入队的元素
*/
void push_queue(Seqqueue* queue, ElemType value)
{
	//判断队列是否满了
	if(queue->rear == MAXSIZE)
	{
		printf("队列已经满了,无法进行入队操作\n");
		return ;
	}

	//data[rear]
	queue->data[queue->rear] = value;	//向队列中添加元素
	queue->rear++;						//队尾"指针"去到下一个入队的位置
}

/*
	功能: 出队
	参数:
		queue: 队列的地址
	返回值:
		成功返回出队元素的数据
		失败返回0
*/
ElemType pop_queue(Seqqueue* queue)
{
	//判断队列是否为空
	if(queue_empty(queue))
	{
		printf("队列已空,无法进行出队操作\n");
		return 0;
	}

	ElemType temp = queue->data[queue->front]; //先保存出队元素的数据
	queue->data[queue->front] = 0;
	queue->front++;			//原来队头后面的那个元素成为新的队头
}

/*
	功能: 获取队头元素的数据
	参数:	
		queue: 队列的地址
	返回值:
		成功返回队头元素的数据
		失败返回0	
*/
ElemType get_front(Seqqueue* queue)
{
	//判断队列是否为空
	if(queue_empty(queue))
	{
		printf("队列已空,无法进行出队操作\n");
		return 0;
	}
	else
	{
		return queue->data[queue->front];  //data[front]
	}
}

/*
	功能: 判断队列是否为空
	参数:
		队列的地址
	返回值:
		为空返回 true
		不为空返回 flase
*/
bool queue_empty(Seqqueue* queue)
{
	//在此队列中,当队头和队尾的位置一致时,认为队列为空
	if(queue->front == queue->rear)
		return true;

	return false;
}

Seqqueue* destory_queue(Seqqueue* queue)
{
	while(1)
	{
		//如果队列为空,则跳出循环
		if(queue_empty(queue))
			break;

		//不断的进行出队操作
		pop_queue(queue);
	}

	free(queue);
	queue = NULL;

	return queue;
}

seqqueue.h

#ifndef		__SEQQUEUE_H__
#define		__SEQQUEUE_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef int ElemType;

#define	MAXSIZE 10

typedef struct Seqqueue
{
	ElemType data[MAXSIZE];		//数据域
	int front;					//队头"指针"
	int rear;					//队尾"指针"
}Seqqueue;

Seqqueue* queue_init();

void push_queue(Seqqueue* queue, ElemType value);

ElemType pop_queue(Seqqueue* queue);

ElemType get_front(Seqqueue* queue);

bool queue_empty(Seqqueue* queue);

Seqqueue* destory_queue(Seqqueue* queue);




#endif

main.c

#include "seqqueue.h"

int main()
{
	//创建一个空的队列
	Seqqueue* queue = queue_init();

	//出队
	pop_queue(queue);

	//入队
	push_queue(queue, 100);
	push_queue(queue, 200);
	push_queue(queue, 300);

	//获取队头元素的数据
	int front_data = get_front(queue);
	if(front_data != 0)
		printf("front_data = %d\n", front_data);

	
	//出队
	pop_queue(queue);
	front_data = get_front(queue);
	if(front_data != 0)
		printf("front_data = %d\n", front_data);

	//销毁队列
	queue = destory_queue(queue);

	push_queue(queue, 500);

	return 0;
}




















循环队列代码:

Circlequeue.c

#include "Circlequeue.h"


/*
	功能: 创建一个空的队列
	返回值:
		队列的地址
*/
Seqqueue* queue_init()
{
	Seqqueue* queue = malloc(sizeof(Seqqueue));

	queue->front = 0;
	queue->rear = 0;	//一开始,队头和队尾在同一位置,表示队列为空

	return queue;
}

/*
	功能: 入队
	参数:
		queue: 队列的地址
		value: 需要入队的元素
*/
void push_queue(Seqqueue* queue, ElemType value)
{
	//判断队列是否满了
	if((queue->rear+1)%MAXSIZE == queue->front)
	{
		printf("队列已经满了,无法进行入队操作\n");
		return ;
	}

	//data[rear]
	queue->data[queue->rear] = value;	//向队列中添加元素
	queue->rear = (queue->rear+1)%MAXSIZE; //队尾"指针"去到下一个入队的位置
}

/*
	功能: 出队
	参数:
		queue: 队列的地址
	返回值:
		成功返回出队元素的数据
		失败返回0
*/
ElemType pop_queue(Seqqueue* queue)
{
	//判断队列是否为空
	if(queue_empty(queue))
	{
		printf("队列已空,无法进行出队操作\n");
		return 0;
	}

	ElemType temp = queue->data[queue->front]; //先保存出队元素的数据
	queue->data[queue->front] = 0;
	queue->front = (queue->front+1)%MAXSIZE;//原来队头后面的那个元素成为新的队头
}

/*
	功能: 获取队头元素的数据
	参数:	
		queue: 队列的地址
	返回值:
		成功返回队头元素的数据
		失败返回0	
*/
ElemType get_front(Seqqueue* queue)
{
	//判断队列是否为空
	if(queue_empty(queue))
	{
		printf("队列已空,无法进行出队操作\n");
		return 0;
	}
	else
	{
		return queue->data[queue->front];  //data[front]
	}
}

/*
	功能: 判断队列是否为空
	参数:
		队列的地址
	返回值:
		为空返回 true
		不为空返回 flase
*/
bool queue_empty(Seqqueue* queue)
{
	//在此队列中,当队头和队尾的位置一致时,认为队列为空
	if(queue->front == queue->rear)
		return true;

	return false;
}

Seqqueue* destory_queue(Seqqueue* queue)
{
	while(1)
	{
		//如果队列为空,则跳出循环
		if(queue_empty(queue))
			break;

		//不断的进行出队操作
		pop_queue(queue);
	}

	free(queue);
	queue = NULL;

	return queue;
}

Circlequeue.h

#ifndef		__CIRCLEQUEUE_H__
#define		__CIRCLEQUEUE_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef int ElemType;

#define	MAXSIZE 5

typedef struct Seqqueue
{
	ElemType data[MAXSIZE];		//数据域
	int front;					//队头"指针"
	int rear;					//队尾"指针"
}Seqqueue;

Seqqueue* queue_init();

void push_queue(Seqqueue* queue, ElemType value);

ElemType pop_queue(Seqqueue* queue);

ElemType get_front(Seqqueue* queue);

bool queue_empty(Seqqueue* queue);

Seqqueue* destory_queue(Seqqueue* queue);




#endif

main.c

#include "Circlequeue.h"

int main()
{
	//创建一个空的队列
	Seqqueue* queue = queue_init();

	//出队
	pop_queue(queue);

	//入队
	push_queue(queue, 100);
	push_queue(queue, 200);
	push_queue(queue, 300);
	push_queue(queue, 400);
	push_queue(queue, 500);

	//获取队头元素的数据
	int front_data = get_front(queue);
	if(front_data != 0)
		printf("front_data = %d\n", front_data);
	
	//出队
	pop_queue(queue);
	front_data = get_front(queue);
	if(front_data != 0)
		printf("front_data = %d\n", front_data);

	//入队
	push_queue(queue, 600);

	//销毁队列
	queue = destory_queue(queue);

	push_queue(queue, 500);

	return 0;
}




















链式队列代码:

queue.c

#include "queue.h"

/*
	功能: 初始化一个头结点(存储队列的一些属性信息)
	返回值:
		返回头结点的地址
*/
Queue* queue_init()
{
	Queue* queue = malloc(sizeof(Queue));

	queue->front = NULL;
	queue->rear = NULL;
	queue->num = 0;

	return queue;
}

/*
	功能: 初始化一个新的结点
	参数:
		value: 结点数据域的值
	返回值:
		返回这个新的结点的地址
*/
queue_node* node_init(ElemType value)
{
	queue_node* new_node = malloc(sizeof(queue_node));

	new_node->data = value;
	new_node->next = NULL;

	return new_node;
}

/*
	功能: 入队(往链表最后插入新的结点)
	参数:
		queue: 队列头结点的地址
		value: 需要入队的元素的数据
*/
void push_queue(Queue* queue, ElemType value)
{
	//初始化一个新的结点
	queue_node* new_node = node_init(value);

	//从无到有
	if(queue->front == NULL)
	{
		queue->front = new_node;
		queue->rear = new_node;
	}
	//从少到多
	else
	{
		//往链表最后插入新的结点 ==> 尾插
		queue->rear->next = new_node;  
		queue->rear = new_node;		//新入队的元素接在原来队列的最后一个元素后面
	}

	queue->num++;		//队列中元素的个数加一
}


/*
	功能: 出队(删除链表中的第一个结点)
	参数:
		队列的头结点的地址
	返回值:
		成功返回出队元素的数据
		失败返回0
*/
ElemType pop_queue(Queue* queue)
{
	if(queue->num == 0)
	{
		printf("队列已空,无法进行出队操作\n");
		return 0;
	}

	ElemType value;//保存出队的元素的数据

	//队列中只有一个元素
	if(queue->front->next == NULL)
	{
		value = queue->front->data;
		queue_node* p = queue->front; //先保存需要释放的结点的地址
		queue->front = NULL;
		queue->rear = NULL;
		free(p);
	}
	else
	//队列中有多个元素
	{
		value = queue->front->data;
		queue_node* p = queue->front; //先保存需要释放的结点的地址
		queue->front = queue->front->next; //原来队列中的第二个元素成为新的队头
		p->next = NULL;
		free(p);
	}

	queue->num--;

	return value;
}

/*
	功能: 获取队头元素的数据
	参数:
		queue: 队列头结点的地址
	返回值:
		成功返回队头元素的数据
		失败返回0
*/
ElemType get_front(Queue* queue)
{
	if(queue->num != 0)
		return  queue->front->data;
	else
		printf("队列已空,无法获取队头元素的数据\n");

	return 0;
}

/*
	功能: 销毁一个队列
	参数:
		queue: 队列的头结点的地址
	返回值:
		NULL
*/
Queue* destory_queue(Queue* queue)
{
	queue_node* p = queue->front; //遍历整个队列
	queue_node* p_next = NULL;		//用来保存此时待删除结点的下一个结点的地址

	while(p != NULL)
	{
		p_next = p->next; //保存此时待删除结点的下一个结点的地址
		p->next = NULL;
		free(p);
		p = p_next;		//继续往后遍历
	}

	queue->front = NULL;
	queue->rear = NULL;
	queue->num = 0;
	free(queue);
	queue = NULL;

	return queue;
}





queue.h

#ifndef		__QUEUE_H__
#define		__QUEUE_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef int ElemType;

typedef struct queue_node
{
	ElemType data;				//数据域
	struct queue_node* next;	//指针域
}queue_node;


typedef struct Queue 
{
	queue_node* front;		//队头指针,保存队头元素的地址
	queue_node*	rear;		//队尾指针,保存队尾元素的地址
	int num;				//队列中元素的个数	
}Queue;

Queue* queue_init();

queue_node* node_init(ElemType value);

void push_queue(Queue* queue, ElemType value);

ElemType pop_queue(Queue* queue);

ElemType get_front(Queue* queue);

Queue* destory_queue(Queue* queue);


#endif


main.c

#include "queue.h"


int main()
{
	Queue* queue = queue_init();

	//出队
	pop_queue(queue);

	//入队
	push_queue(queue, 100);
	push_queue(queue, 200);
	push_queue(queue, 300);

	ElemType front_data = get_front(queue);
	if(front_data != 0)
		printf("front_data = %d\n", front_data);

	//出队
	pop_queue(queue);
	front_data = get_front(queue);
	if(front_data != 0)
		printf("front_data = %d\n", front_data);

	//销毁队列
	queue = destory_queue(queue);
	push_queue(queue, 500);

	return 0;
}






















中缀表达式转后缀表达式代码:

houzhui.c

#include "houzhui.h"


/*
	功能: 获取一个运算符的优先级
	参数:
		op: 运算符
	返回值:
		返回这个运算符的优先级
*/
int get_priority(char op)
{
	if(op == '+' || op == '-')
		return 1;

	if(op == '*' || op == '/')
		return 2;
}

/*
	功能: 运算符的入栈
	参数:
		stack: 栈的头结点地址
		queue: 队列头结点的地址
		op : 运算符
*/
void push_operator_stack(Stack* stack, Queue* queue, char op)
{
	char sop[2] = {op, '\0'}; //存储运算符

	//如果栈不为空,则需要比较入栈的运算符与栈顶元素的优先级
	while(stack_empty(stack) == false)
	{
		//如果待入栈的运算符的优先级比栈顶元素优先级高,则直接入栈
		if(get_priority(op) > get_priority(get_top(stack)[0]))
		{
			push_stack(stack, sop);
			return ;
		}
		//否则,需要把栈顶元素弹出,并进行入队,继续比较待入栈元素与新的栈顶元素的优先级
		else
		{
			ElemType* top_data = pop_stack(stack); //获取栈顶元素的数据并进行出栈
			push_queue(queue, top_data); //将出栈的元素进行入队
		}
	}

	//如果栈为空,则直接入栈
	push_stack(stack, sop);
	
}



/*
	功能: 中缀表达式转化为后缀表达式
	参数:
		stack: 栈的头结点的地址
		queue: 队列的头结点的地址
		express: 需要进行转化的中缀表达式
*/
void convert_mid_express(Stack* stack, Queue* queue, ElemType* express)
{
	//1、数据域为字符串
	//2、先建立一个空的栈和一个空的队列
	//3、定义一个字符数组,存储中缀表达式

	char temp[10] = {0}; //用来保存中缀表达式中的数字字符
	int pos = 0;	//偏移量,用来协助数字字符的存储
	
	//4、遍历中缀表达式,并判断遇到的字符是数字还是运算符
	for(int i = 0; i < strlen(express); i++)
	{
		//5、如果是数字,则存入字符数组
		if(express[i] >= '0' && express[i] <= '9')
		{
			temp[pos] = express[i];
			pos++;
		}
		else
		{
			//6、如果是运算符,则将字符数组中的数据入队,再根据规则对运算符进行入栈操作
			push_queue(queue, temp);
			memset(temp, 0, sizeof(temp)); //将temp这个数组清空
			pos = 0;	//偏移量置零
			//运算符入栈
			push_operator_stack(stack, queue, express[i]);
		}
	}
	//最后一个数字字符串存储在temp中,需要手动进行入队
	push_queue(queue, temp);

	//7、中缀表达式遍历完毕之后,将栈中的元素依次出栈并进行入队
	while(stack_empty(stack) == false)
	{
		ElemType* top_data = pop_stack(stack);
		push_queue(queue, top_data);
	}
}




















houzhui.h

#ifndef		__HOUZHUI_H__
#define		__HOUZHUI_H__

#include "queue.h"
#include "Stack.h"

int get_priority(char op);
void push_operator_stack(Stack* stack, Queue* queue, char op);
void convert_mid_express(Stack* stack, Queue* queue, ElemType* express);


#endif 

main.c

#include "queue.h"
#include "stack.h"
#include "houzhui.h"

int main()
{
/*
	Queue* queue = queue_init();

	//出队
	pop_queue(queue);

	//入队
	push_queue(queue, "hello");
	push_queue(queue, "hahahaha");
	push_queue(queue, "oooo");

	print_queue(queue);

	ElemType* front_data = get_front(queue);
	if(front_data != NULL)
		printf("front_data = %s\n", front_data);

	//出队
	pop_queue(queue);
	front_data = get_front(queue);
	if(front_data != NULL)
		printf("front_data = %s\n", front_data);

	//销毁队列
	queue = destory_queue(queue);
	push_queue(queue, "hhh");
*/

/*
	//初始化一个空的栈
	Stack* stack = stack_init();

	//出栈
	pop_stack(stack);  

	//入栈
	push_stack(stack, "hello");
	push_stack(stack, "world");
	push_stack(stack, "hahahaha");

	ElemType* top_data = get_top(stack);
	if(top_data != NULL)
		printf("top_data = %s\n", top_data);

	//出栈
	ElemType* pop_data = pop_stack(stack);
	printf("pop_data = %s\n", pop_data);
	free(pop_data);

	top_data = get_top(stack);
	if(top_data != NULL)
		printf("top_data = %s\n", top_data);
*/

	//对栈和队列进行初始化
	Stack* stack = stack_init();
	Queue* queue = queue_init();

	//中缀表达式 100 + 200 * 3 / 2
	//ElemType express[20] = "1+2*3";  //1 2 3 * +
	ElemType express[20] = "100+200*3/2"; //100 200 3 * 2 / +

	//中缀转后缀
	convert_mid_express(stack, queue, express);

	//打印队列
	print_queue(queue);

	
	return 0;
}






















  • 20
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值