栈和队列的应用

栈的应用

括号匹配

在这里插入图片描述

最后出现的的左括号最先被匹配(LIFO)
将左括号依次压入栈中,越晚压入栈的左括号,越早被弹出
可用栈实现该特性
在这里插入图片描述

遇到左括号,压入栈中;遇到右括号,就把位于栈顶的左括号弹出,消耗(出栈)一个左括号,然后检查两个是否匹配(小对小,中对中,大对大)。

举例:
匹配情况 :
在这里插入图片描述

不匹配情况:
1.当前扫描到的右括号与栈顶左括号不匹配在这里插入图片描述
2.扫描到右括号且栈空(右括号单身)
在这里插入图片描述

3.处理完所有括号后,栈非空(左括号单身)
在这里插入图片描述
流程图:
在这里插入图片描述
代码实现:

#include<stdio.h>
#define MAX 10
//顺序栈定义
typedef struct{
	char data[MAX];
	int top;
}SqStack;

bool bracket(char str[],int length){
	SqStack S;
	S.top=-1;
	for(int i=0;i<length;i++){
		if (str[i]=='{' || str[i]=='['|| str[i]=='('){
		//左括号压入栈中
			if (S.top==MAX-1)
				return false;
			S.top=S.top+1;
			S.data[S.top]=str[i];
		}
		else {
		//判断栈是否为空,右括号单身
			if (S.top==-1)
				return false;
			//判断右括号是否和栈顶的左括号匹配
			char topElem;
			topElem=S.data[S.top];
			S.top=S.top-1;
			if (str[i]=='}'&& topElem!='{')
				return false;
			if(str[i]==']'&&topElem!='[')
				return false;
			if(str[i]==')'&&topElem!='(')
				return false;
		}
	}//判断左括号单身
	return (S.top==-1);
}

int main(){
	char str[] = {'(','(',')',')'};
	bool b = bracket(str, 4);
	if(b == true){
		printf("正确");
	}else{
		printf("不正确");
	}
	return 0;
}

表达式求值

算术表达式由三部分组成:操作数、运算符、界限符
后缀表达式(逆波兰表达式):运算符在两个操作数后面
前缀表达式(波兰表达式):运算符在两个操作数前 面
中缀表达式:运算符在两个操作符中间
在这里插入图片描述
中缀转后缀的手算方法:

  1. 确定中缀表达式中各个运算符的运算顺序
  2. 选择下一个运算符,按照「左操作数 右操作数 运算符」的方式组合成一个新的操作数
  3. 如果还有运算符没被处理,就继续2.

左优先原则
只要左边的运算符能先计算,就优先算左边的
可保证运算顺序唯一

后缀表达式的手算方法
从左往右扫描,每遇到一个运算符,就让运算符前面最近的两个操作数执行对应运算,合体为一个操作数。
在这里插入图片描述

  • 特点:最后出现的操作数先被运算 LIFO 栈

用栈实现后缀表达式的计算:

  1. 从左往右扫描下一个元素,直到处理完所有元素
  2. 若扫描到操作数则压入栈,并回到①;否则执行③
  3. 若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,回到①

注意:

  • 先出栈的是“右操作数”
  • 此栈用于存放当前暂时还不能确定运算次序的操作数
    在这里插入图片描述
    中缀表达式转后缀表达式(机算)
    初始化一个栈,用于保存 暂时还不能确定运算顺序的运算符。
    从左到右处理各个元素,直到末尾。可能遇到三种情况:
  1. 遇到操作数。直接加入后缀表达式。
  2. 遇到界限符。遇到 “(” 直接入栈;遇到 “)” 则依次弹出栈内运算符并加入后缀表达式,直到弹出“(”为止。注意: “(” 不加入后缀表达式,弹飞它。
  3. 遇到运算符。依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式。
    若碰到 “(” 或栈空则停止弹出。
    之后再把当前运算符入栈。

按上述方法处理完所有字符后,将栈中剩余运算符依次弹出,并加入后缀表达式。

中缀转前缀的手算方法:

  1. 确定中缀表达式中各个运算符的运算顺序
  2. 选择下一个运算符,按照「运算符 左操作数 右操作数」的方式组合成一个新的操作数 如果还有运算符没被处理,就继续2.

左优先原则:只要右边的运算符能先计算,就优先算右 边的
可保证运算顺序唯一

用栈实现前缀表达式的计算:

  1. 从右往左扫描下一个元素,直到处理完所有元素
  2. 若扫描到操作数则压入栈≥并回到①;否则执行③
  3. 若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,回到①

注意:先出栈的是“左操作数”

中缀表达式的计算(用栈实现):
中缀转后缀+后缀表达式求值 两个算法的结合

  1. 初始化两个栈,操作数栈和运算符栈
  2. 若扫描到操作数,压入操作数栈
  3. 若扫描到运算符或界限符,则按照“中缀转后缀”相同的逻辑压入运算符栈(期间也会弹出运算符,每当弹出一个运算符时,就需要再弹出两个操作数栈的栈顶元素并执行相应运算,运算结果再压回操作数栈)
    在这里插入图片描述

递归

函数调用的特点:最后被调用的函数最先执行结束(LIFO)
函数调用时,需要用一个栈存储:

  1. 调用返回地址
  2. 实参
  3. 局部变量

在这里插入图片描述
适合用“递归”算法解决:可以把原始问题转换为属性相同,但规模较小的问题
在这里插入图片描述

  • 递归调用时,函数调用栈可称为“递归工作栈”
  • 每进入一层递归,就将递归调用所需信息压入栈顶
  • 每退出一层递归,就从栈顶弹出相应信息

在这里插入图片描述
在这里插入图片描述
缺点:效率低太多层递归可能会导致栈溢出;可能包含很多重复计算。

队列的应用

树的层次遍历

初始化:1入队
以下重复:队首元素出队,他的两个孩子入队

  • 首先遍历根节点,即1号节点,遍历到1号节点时,把其左节点2和右节点3放到队尾
  • 遍历完1号节点后1号出队
  • 检查队头的2号节点,将2号节点的左右两个孩子45加到队列队尾
  • 处理完2号节点后2号出队
  • 检查队头的3号节点,将3号节点的左右两个孩子67加到队列队尾
  • 处理完3号节点后3号出队
  • 检查队头的4号节点,4号节点没有左右孩子,不需要在队尾插入任何元素
  • 4号出队

在这里插入图片描述

图的广度优先遍历

  • 遍历1号节点
  • 检查和1号节点相邻的节点有没有被遍历过,将23加入队列
  • 1号出队
  • 检查和1号节点相邻的节点有没有 没有被遍历过的节点,将4加入队列
  • 2号出队
  • 检查和3号节点相邻的节点有没有 没有被遍历过的节点,将56加入队列
  • 3号出队
  • 和4号相邻的节点都被处理过,4号出队
  • 检查5号,将78加入队列
  • 5号出队,6、7、8出队
    在这里插入图片描述

队列在操作系统中的应用

多个进程争抢着使用有限的系统资源时,FCFS (First Come First Service,先来先服务)是一种常用策略。

CPU:
各个APP轮换使用
在这里插入图片描述
打印:
可缓解主机与打印机速度不匹配的问题
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值