【数据结构】栈和队列的应用——括号匹配 + 表达式求值 + 表达式转换 +栈的递归应用+队列在计算机系统中的应用

文章目录

    • 3.栈的应用
      • 3.1 括号匹配问题
      • 3.2 表达式求值
        • 3.2.1 三种算术表达式
        • 3.2.2 后缀表达式
          • A.中缀转后缀
          • B.后缀表达式的计算
        • 3.2.3 前缀表达式
          • A.中缀转前缀
          • B.前缀表达式的计算
        • 3.2.4 中缀表达式的求值
      • 3.3 递归中栈的应用
    • 4.队列的应用

栈基础知识:【数据结构】栈 顺序栈 链栈(共享栈 创建 进栈 出栈 读取)完整代码+解析
队列基础知识:【数据结构】队列 循环队列 双端队列——顺序队列+链式队列完整代码

3.栈的应用

3.1 括号匹配问题

  • 问题阐述

    判断一组有()[]{}这些括号的字符串,判断左右括号是否匹配。

    • 括号需要从里向外一层层匹配,符合栈后进先出的特点,所以用栈解决括号匹配问题。
  • 匹配流程:

  • 算法流程:

    1.创建空栈,顺序遍历括号;

    2.若是左括号,压入栈中,继续扫描;

    3.若是右括号,弹出栈顶元素,判断两个括号类型是否匹配;

    4.遍历完后判断栈是否空。

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

#define ElemType char 
#define MaxSize 9

typedef struct {
	ElemType data[MaxSize];
	int top;
}SqStack;

void InitStack(SqStack& Q) {
	Q.top = -1;
}

bool isEmpty(SqStack& Q) {
	if (Q.top == -1)
		return true;
	else
		return false;
}

bool Push(SqStack& Q, ElemType x) {
	if (Q.top + 1 == MaxSize)return false;
	Q.data[++Q.top] = x;
	return true;
}

bool Pop(SqStack& Q, ElemType& x) {
	if (Q.top == -1)return false;
	x = Q.data[Q.top--];
	return true;
}

//括号匹配算法
bool bracketCheck(char s[],int length) {
	SqStack Q;
	InitStack(Q);
	char topElem;
	for (int i = 0; i < length; i++) {
		if (s[i] == '(' || s[i] == '[' || s[i] == '{') {
			Push(Q, s[i]);
		}
		else {
			Pop(Q, topElem);
			if (s[i] == ')' && topElem == '(' || s[i] == ']' && topElem == '[' || s[i] == '}' && topElem == '{')
				continue;
			else
				return false;
		}
	}
	if (!isEmpty(Q))return false;
	return true;
}

int main() {
	char s1[6] = { '(','(','[',']',')' };
	char s2[4] = { '(','{',']' };
	char s3[7] = { '(','[','{','}',']',')'};

	printf("%d\n",bracketCheck(s1, 5));
	printf("%d\n", bracketCheck(s2, 3));
	printf("%d\n", bracketCheck(s3, 6));
}

3.2 表达式求值

3.2.1 三种算术表达式
  • 中缀表达式

    就是我们日常所用的表达式。

    由操作符、界限符、操作数组成。

    • 运算符在两个操作数中间。
  • 后缀表达式(逆波兰式)

    运算符在两个操作数后面。

  • 前缀表达式(波兰式)

    运算符在两个操作数前面。

3.2.2 后缀表达式
A.中缀转后缀
  • 手算方法

    1.确定中缀表达式中各运算符的运算顺序。

    2.选择下一个运算符,按**【左操作数 右操作数 运算符】方式组合成新的操作数**。

    3.如果还有运算符没被处理,就继续第2步。

    • 注:运算顺序不唯一,对应的后缀表达式也不唯一,但机算是左优先原则。

    • 左优先原则:只要左边的运算符能先计算,就优先算左边。(可确保运算顺序唯一)

  • 机算

    初始化一个栈(用于保存暂时不能确定运算顺序的运算符)

    从左往右处理各元素,直到末尾,可能遇到以下三种情况:

    • 1.遇到操作数

      直接加入后缀表达式;

    • 2.遇到界限符

      遇到‘(’直接入栈;

      遇到‘)’依次弹出栈内运算符并加入后缀表达式,直到弹出‘(’;

    • 3.遇到运算符

      依次弹出栈中优先级高于或等于当前运算符的所有运算符,加入后缀表达式,

      若碰到‘(’或栈空停止,

      再把当前运算符入栈。

  • 中缀转后缀完整代码

    #include<stdio.h>
    #include<string.h>
    
    #define ElemType char
    #define MaxSize 99
    
    typedef struct {
    	ElemType data[MaxSize];
    	int top;
    }SqStack;
    
    void InitStack(SqStack& Q) {
    	Q.top = -1;
    }
    
    bool isEmpty(SqStack& Q) {
    	if (Q.top == -1)
    		return true;
    	else
    		return false;
    }
    
    bool Push(SqStack& Q, ElemType x) {
    	if (Q.top + 1 >= MaxSize)return false;
    
    	Q.data[++Q.top] = x;
    	return true;
    }
    
    bool Pop(SqStack& Q, ElemType& x) {
    	if (Q.top == -1)return false;
    
    	x=Q.data[Q.top--];
    	return true;
    }
    
    //运算符优先级判断
    int Priority(char x) {
    	if (x == '-' || x == '+')
    		return 1;
    	else if (x == '*' || x == '/')
    		return 2;
    	else if (x == '(') 
    		return 0;
    	return -1; 
    }
    
    //中缀转后缀
    //in是待转换的中缀表达式,suf是转换后的前缀表达式
    void in2suf(char in[], char suf[]) {
    	//初始化一个栈
    	SqStack Q;
    	InitStack(Q);
    
    	int isuf = 0;//suf数组下标
    	char x;
    
    	//从左往右遍历各元素
    	for (int i = 0; i < strlen(in); i++) {
    		if (in[i] >= '0' && in[i] <= '9') //遇到操作数。
    		{
    			suf[isuf++] = in[i]; //直接加入后缀表达式
    		}
    		else if (in[i] == '(') //遇到‘(’
    		{
    			Push(Q, in[i]); //直接入栈
    		}
    		else if (in[i] == ')')  //遇到‘)’
    		{
    			Pop(Q, x); //依次弹出栈内运算符
    			while (x != '(') {
    				suf[isuf++] = x; //并加入后缀表达式
    				Pop(Q, x);
    			}	
    		}
    		else //遇到运算符
    		{ 
    			//依次弹出栈中优先级高于或等于当前运算符的所有运算符
    			while (!isEmpty(Q)&&Priority(in[i]) <= Priority(Q.data[Q.top])) {
    				if (Q.data[Q.top] == '(')break; //若碰到‘(’或栈空停止
    				Pop(Q, x);
    				suf[isuf++] = x; //加入后缀表达式
    			}
    			Push(Q, in[i]); //当前运算符入栈
    		}
    	}
    	while (!isEmpty(Q)){
    		Pop(Q, x);
    		suf[isuf++] = x;
    	}
    	suf[isuf] = '\0';
    }
    
    int main() {
    	char in[] = "1+5*(2+3)/(4-2)+3*1";
    	char suf[MaxSize];
    	in2suf(in, suf);
    	printf("%s\n", in);
    	printf("%s\n\n", suf);
    	return 0;
    }
    

    在这里插入图片描述

B.后缀表达式的计算
  • 手算

    从左往右扫描,遇到一个运算符,就让运算符前面最近的两个操作数执行对应运算,合并为一个操作数。

  • 机算

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

    1.从左往右扫描下一个元素,直到处理完所有元素;

    2.若扫描到操作数则压入栈,并返回第1步,否则执行第3步;

    3.若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,回到第1步。

  • 后缀表达式求值 完整代码

    #define  _CRT_SECURE_NO_WARNINGS
    #include<stdio.h>
    #include<string.h>
    
    #define ElemType int
    #define MaxSize 99
    
    typedef struct {
    	ElemType data[MaxSize];
    	int top;
    }SqStack;
    
    void InitStack(SqStack& Q) {
    	Q.top = -1;
    }
    
    bool isEmpty(SqStack& Q) {
    	if (Q.top == -1)
    		return true;
    	else
    		return false;
    }
    
    bool Push(SqStack& Q, ElemType x) {
    	if (Q.top + 1 >= MaxSize)return false;
    
    	Q.data[++Q.top] = x;
    	return true;
    }
    
    bool Pop(SqStack& Q, ElemType& x) {
    	if (Q.top == -1)return false;
    
    	x = Q.data[Q.top--];
    	return true;
    }
    
    //后缀表达式求值
    int Computed_suf(char suf[]) {
    	SqStack Q;
    	InitStack(Q);
    	int a, b,c;
    	//从左往右扫描下一个元素,直到处理完所有元素
    	for (int i = 0; i < strlen(suf); i++) {
    		if (suf[i] >= '0' && suf[i] <= '9') { //若扫描到操作数则压入栈
    			Push(Q, suf[i]-'0');
    		}
    		else { //若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶
    			Pop(Q, b);
    			Pop(Q, a);
    			if (suf[i] == '+') {
    				c = a + b;
    			}
    			else if (suf[i] == '-') {
    				c = a - b;
    			}
    			else if (suf[i] == '*') {
    				c = a * b;
    			}
    			else if (suf[i] == '/') {
    				c = a / b;
    			}
    			Push(Q, c);
    		}
    	}
    	return Q.data[Q.top];
    }
    
    int main() {
    	char s[] = "1523+*72-/+31*+"; //1+5*(2+3)/(7-2)+3*1=9
    	printf("%d", Computed_suf(s));
    	return 0;
    }
    
3.2.3 前缀表达式
A.中缀转前缀
  • 手算

    1.确定运算顺序;

    2.选择下一个运算符,按【运算符 左操作数 右操作数】的方式组合成新操作数;

    3.如果还有运算符没被处理,重复第2步。

    • 右优先原则:只要右边运算符能先计算,就优先算右边。

B.前缀表达式的计算

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

1.从右往左扫描下一个元素,直到全部处理完;

2.若扫描到操作符则压入栈,返回第1步,否则执行第3步;

3.遇到运算符,弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,返回第1步。

  • 注:在弹出的两个栈顶元素中,先出栈的是左操作数。
3.2.4 中缀表达式的求值
  • 方法

    用栈实现,就是中缀转后缀+后缀表达式计算

    1.初始化两个栈:操作数栈+运算符栈;

    2.若扫描到运算符或界限符,则按中缀转后缀相同逻辑压入运算符栈

3.3 递归中栈的应用

  • 函数调用特点

    最后被调用的函数最先执行结束(LIFO)

  • 调用函数时,需要用一个栈存储:

    1.调用返回地址;

    2.实参;

    3.局部变量。

  • 递归的精髓:

    将原始问题转换为属性相同但规模较小的小问题。

    大问题---->小问题

    • 但通常情况下,递归能减少代码量但效率不高
  • 在计算机中,用栈来解决函数的递归调用

    递归调用时,函数调用栈可称为“递归工作栈”,

    每进入一层递归,就将递归调用所需信息压入栈,

    每退出一层递归,就从栈顶弹出相应信息。

    • 通俗的说:函数调用,就是函数入栈;函数得到值,就是栈的弹出;

    • 缺点:递归太多可能导致栈溢出。

4.队列的应用

  • 树的层次遍历、图的广度优先遍历

  • 队列在计算机系统中的应用

    • 多队列的应用

      多个进程抢有限的系统资源时,FCFS(先来先服务)是常见策略。

    • 打印数据缓冲区

      在缓冲区中,用队列组织打印数据,

      可缓解主机与打印机速度不匹配问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/438827.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

react tab选项卡吸顶实现

react tab选项卡吸顶实现&#xff0c;直接上代码&#xff08;代码有注释&#xff09; tsx代码 /* eslint-disable react-hooks/exhaustive-deps */ import React, { useEffect, useState } from "react"; import DocumentTitle from react-document-title import s…

python界面开发 - Menu (popupmenu) 右键菜单

文章目录 1. python图形界面开发1.1. Python图形界面开发——Tkinter1.2. Python图形界面开发——PyQt1.3. Python图形界面开发——wxPython1.4. Python图形界面开发—— PyGTK&#xff1a;基于GTK1.5. Python图形界面开发—— Kivy1.6. Python图形界面开发——可视化工具1.7. …

交友盲盒系统PHP开源的盲盒源码

源码介绍&#xff1a; 交友盲盒系统是一款基于PHP开发的开源免费盲盒系统&#xff0c;旨在为用户提供一个充满乐趣和惊喜的社交体验。该系统具有丰富的功能和灵活的扩展性&#xff0c;可以轻松地满足各种线上交友、抽奖活动等场景的需求。 安装说明&#xff1a; PHP版本&…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:CheckboxGroup)

多选框群组&#xff0c;用于控制多选框全选或者不全选状态。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 CheckboxGroup(options?: CheckboxGroupOptions) 创建多选框群组…

以人为本的AI技术升级

我们需要以人为本的技术来提高生产力和投资回报率。 通过在数据标注流程中融合机器学习辅助技术&#xff0c;可以减少数据标注所需的时间、资金和人力。 有很多方法可以防止标注员被模型的预测误导。 在传统的机器学习&#xff08;Machine Learning&#xff09;方法下&#…

阿珊比较Vue和React:两大前端框架的较量

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【HarmonyOS】ArkTS-箭头函数

箭头函数 箭头函数是 比普通函数 更简洁 的一种函数写法 () > {}() > {// 函数体 }let 函数名 () > {// 函数体 }let 函数名 () > {// 函数体 } 函数名(实参1, 实参2)let 函数名 (形参1: 类型, 形参2: 类型) > {// 函数体 } 函数名(实参1, 实参2)let 函数名 …

99.qt qml-单例程序实现

在之前讲过: 58.qt quick-qml系统托盘实现https://nuoqian.blog.csdn.net/article/details/121855993 由于,该示例只是简单讲解了系统托盘实现,并没有实现单例程序,所以多次打开后就会出现多个exe出现的可能,本章出一章QML单例程序实现, 多次打开始终只显示出第一个打开…

1.5如何缓解图像分类任务中训练数据不足带来的问题?

1.5 图像数据不足时的处理方法 场景描述 在机器学习中&#xff0c;绝大部分模型都需要大量的数据进行训练和学习(包括有监督学习和无监督学习)&#xff0c;然而在实际应用中经常会遇到训练数据不足的问题。 比如图像分类&#xff0c;作为计算机视觉最基本的任务之一&#xff0…

Bytebase 签约合思,覆盖多云数据库变更发布,数据访问控制,安全治理的全生命周期,确保符合合规审计要求

在数字化快速发展时代&#xff0c;有效的规范数据库管理对企业安全运营至关重要。近日&#xff0c;数据库 DevOps 团队协同管理工具 Bytebase 签约费控领域领军企业合思&#xff0c;旨在全面优化数据库操作管理&#xff0c;收口全体员工的变更和查询操作&#xff0c;以提高整体…

基于Nodejs使用Playwright时的一款VSCode插件

上一篇文章讲解了Playwright框架&#xff08;基于nodejs&#xff0c;使用playwright对网站进行爬虫&#xff09;&#xff0c;并基于Nodejs进行了网站爬虫。这篇文章&#xff0c;我们来讲一个选择Nodejs的原因&#xff1a;vscode中的浏览器模拟插件 vscode中的浏览器模拟插件 P…

vue2【详解】生命周期(含父子组件的生命周期顺序)

1——beforeCreate&#xff1a;在内存中创建出vue实例&#xff0c;数据观测 (data observer) 和 event/watcher 事件配置还没调用&#xff08;data 和 methods 属性还没初始化&#xff09; 【执行数据观测 (data observer) 和 event/watcher 事件配置】 2——created&#xf…

微信小程序开发系列(二十二)·wxml语法·双向数据绑定model:的用法

目录 1. 单向数据绑定 2. 双向数据绑定 3. 代码 在 WXML 中&#xff0c;普通属性的绑定是单向的&#xff0c;例如&#xff1a;<input value"((value))"/> 如果希望用户输入数据的同时改变 data 中的数据&#xff0c;可以借助简易双向绑定机制。在对应属性…

项目解决方案:视频监控接入和录像系统设计方案(上)

目 录 1.概述 2. 建设目标及需求 2.1建设总目标 2.2 需求描述 2.3 需求分析 3.设计依据与设计原则 3.1设计依据 3.2 设计原则 &#xff08;1&#xff09;、先进性与适用性 &#xff08;2&#xff09;、经济性与实用性 &#xff08;3&#xff09;、可靠性与…

【机器学习】实验6,基于集成学习的 Amazon 用户评论质量预测

清华大学驭风计划课程链接 学堂在线 - 精品在线课程学习平台 (xuetangx.com) 代码和报告均为本人自己实现&#xff08;实验满分&#xff09;&#xff0c;此次代码开源大家可以自行参考学习 有任何疑问或者问题&#xff0c;也欢迎私信博主&#xff0c;大家可以相互讨论交流哟…

离散数学例题——5.图论基础

基本的图 关联矩阵 子图和补图 度数和握手定理 注意&#xff01;&#xff01;&#xff01;无向图的度数&#xff0c;要行/列和对角线值 根据度数序列判定是否为无向图 度和握手定理证明题 竞赛图 同构图 自补图 通路和回路数量 通路和回路数量 最短路径——dijkstra算法 连通…

ThreadLocal :在 Java中隱匿的魔法之力

优质博文&#xff1a;IT-BLOG-CN ThreadLocal 并不是一个Thread&#xff0c;而是 ThreadLocalVariable(线程局部变量)。也许把它命名为 ThreadLocalVar更加合适。线程局部变量就是为每一个使用该变量的线程都提供一个变量值的副本&#xff0c;是 Java中一种较为特殊的线程绑定机…

SpringAMQP创建交换机和队列

SpringAMQP提供的Exchange接口 一基于bean注解: 一.Fanout交换机 package com.itheima.consumer.config;import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.FanoutExchang…

【MySQL 系列】MySQL 架构篇

在我们开始了解 MySQL 核心功能之前&#xff0c;首先我们需要站在一个全局的视角&#xff0c;来看 SQL 是如何运作执行的。通过这种方式&#xff0c;我们可以在头脑中构建出一幅 MySQL 各组件之间的协同工作方式&#xff0c;有助于我们加深对 MySQL 服务器的理解。 文章目录 1、…

【洛谷 P8662】[蓝桥杯 2018 省 AB] 全球变暖 题解(深度优先搜索+位集合)

[蓝桥杯 2018 省 AB] 全球变暖 题目描述 你有一张某海域 N N N \times N NN 像素的照片&#xff0c;. 表示海洋、 # 表示陆地&#xff0c;如下所示&#xff1a; ....... .##.... .##.... ....##. ..####. ...###. .......其中 “上下左右” 四个方向上连在一起的一片陆地组…