stack 中缀表达式求值

news2025/1/20 7:26:31

【解法一】双栈思路梳理

【解法二】利用逆波兰表达式求解(中缀转后缀)


这个有俩种方法,一是直接根据条件进行各种情况的推导直接由中缀表达式求解,

                            二就是将中缀表达式转化为后缀表达式,利用更容易的逆波兰表达式求解方法

描述

        请写一个整数计算器,支持加减乘三种运算和括号。

        数据范围:0≤∣s∣≤1000≤∣s∣≤100,保证计算结果始终在整型范围内

【解法一】双栈思路梳理

最基本的就是遍历字符串给出一个访问遍历i=0;使用num栈来存放数字,使用ops栈来存放运算符

从各种情况慢慢演练:

① 当遍历为数字,那么直接入栈 也不能简单的直接将s[i]入栈,当然要连带它后面的数字进行判断,将一整个数字比如135入栈,下面源码的toInt函数哩就展示的这一功能,唯一注意点,就是需要给i取个引用,使之能通过形参的修改改变到实参。

② 当遍历为+-* 运算符时,如果ops栈为空 入ops栈(这个容易理解就不举例子了)

                                     我当前遍历符号的优先级大于栈顶元素优先级,那么直接入栈

                                    当遍历符号优先级小于栈顶元素优先级,取出2个操作数和一个操作符运算

 

 ③ 当为左括号 直接入ops栈

④ 当为右括号时,停在这个位置,把当前栈中的所有可操作运算进行执行

                           直到遇到之前放入的左括号为止 然后把这个左括号弹出,i也继续访问下一个元素

 ⑤ 当字符串s访问结束之后,还会剩余一些同级别操作符,把他们取出来依次计算即可如下:

 源码:


class Solution {
  public:
    int toInt(string s, int& i) {
        int count = 0;
        int j = i;
        while (s[i] >= '0' && s[i] <= '9') {
            i++;
            count++;
        }
        string temp = (s.substr(j, count));
        return atoi(temp.c_str());
    }
    int solve(string s) {
        // write code here
        map<char, int> mp;
        mp['-'] = 1;
        mp['+'] = 1;
        mp['*'] = 2;
        mp['('] = 0;
        stack<int> num;
        // num.push(0);
        stack<char> ops;
        int i = 0;
        while (i < s.size()) {
            if (s[i] == '+' || s[i] == '-' || s[i] == '*') {
                if (ops.empty() || mp[s[i]] > mp[ops.top()])
                    ops.push(s[i++]);
                else {
                    int right = num.top();
                    num.pop();
                    int left = num.top();
                    num.pop();
                    switch (ops.top()) {
                        case '+':
                            num.push(left + right);
                            break;
                        case '-':
                            num.push(left - right);
                            break;
                        case '*':
                            num.push(left * right);
                            break;
                    }
                    ops.pop();
                    ops.push(s[i++]);
                }
            } else if (s[i] == '(') {
                ops.push(s[i++]);
            } else if (s[i] == ')') {
                while (ops.top() != '(') {
                    int right = num.top();
                    num.pop();
                    int left = num.top();
                    num.pop();
                    switch (ops.top()) {
                        case '+':
                            num.push(left + right);
                            break;
                        case '-':
                            num.push(left - right);
                            break;
                        case '*':
                            num.push(left * right);
                            break;
                    }
                    ops.pop();
                }
                ops.pop();
                i++;
            } else {
                num.push(toInt(s, i));
            }
        }
        while (!ops.empty()) {
            int right = num.top();
            num.pop();
            int left = num.top();
            num.pop();
            switch (ops.top()) {
                case '+':
                    num.push(left + right);
                    break;
                case '-':
                    num.push(left - right);
                    break;
                case '*':
                    num.push(left * right);
                    break;
            }
            ops.pop();
        }
        return num.top();
    }
};

【解法二】利用逆波兰表达式求解(中缀转后缀)

逼站2分钟视频【逆波兰 - 上(中缀表达式 转 后缀表达式)】 https://www.bilibili.com/video/BV1xp4y1r7rc/?share_source=copy_web&vd_source=fc7e83e7f96712b431615535fe32fb1b

(1)若取出的字符是操作数 (eg, 6, 3, 7 ),则分析出完整的运算数,该操作数直接送入res。
(2)若取出的字符是运算符 (eg: ( * / - )),则将该运算符与S1栈栈顶元素比较,如果该运算符(不包括括号运算符)优先级高于S1栈栈顶运算符(包括左括号)优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入res中,直至S1栈栈顶运算符(包括左括号)低于(不包括等于)该运算符优先级时停止弹出运算符,最后将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符。
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
如果表达式结束,但栈中还有元素,将所有元素出栈,添加到后缀表达式中


源码:

#include<map>
#include<stack>
#include<string>
class solution
{
	// 中缀转后缀
public:
	string toInt(string s, int& i) {
		int count = 0;
		int j = i;
		while (s[i] >= '0' && s[i] <= '9') {
			i++;
			count++;
		}
		return string(s.substr(j, count));
	}
	string solve(string s)
	{
		map<char, int> mp;
		mp['('] = 0;
		mp['+'] = 1;
		mp['-'] = 1;
		mp['*'] = 2;
		mp['/'] = 2;
		stack<char> ops;
		string res;
		int i = 0;
		while (i < s.size())
		{
			if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/')
			{
				if (ops.empty() || mp[s[i]] > mp[ops.top()])
					ops.push(s[i++]);
				else
				{
					while (!ops.empty() && mp[s[i]] < mp[ops.top()])
					{
						res += ops.top();
						ops.pop();
					}
					i++;
				}
			}
			else if(s[i] == '(')
				ops.push(s[i++]);
			else if (s[i] == ')')
			{
				while (ops.top()!= '(')
				{
					res += ops.top();
					ops.pop();
				}
				i++;
				ops.pop();
			}
			else
			{
				res += toInt(s, i);
			}
		}
		while (!ops.empty())
		{
			res += ops.top();
			ops.pop();
		}
		return res;
	}
};

int main()
{
	solution ss;
	cout << "请输入中缀表达式" << endl;
	string s;
	cin >> s;
	cout << "中缀表达式为:";
	fflush(stdout);
	cout<<ss.solve(s);
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享微信小程序开发详细步骤

1、梳理小程序开发功能需求自己可以用思维导图写出自己想要开发的小程序里面&#xff0c;需要设置哪些功能&#xff0c;这些功能帮助我解决什么问题。然后把想法用文字形式在思维导图中写出来。如果不知道如果梳理&#xff0c;也可以找专业的产品经理协助处理。如果不知道功能可…

Vector - VT System - CANCANFDLIN板卡_VT6104|6204

对于做车载开发或者测试的朋友来说&#xff0c;大部分对于CANoe&#xff08;VN1600系列&#xff09;是相当的熟悉&#xff0c;我们知道CANoe支持CAN&CANFD&LIN&#xff0c;都有对应的硬件来匹配&#xff1b;但是如果需要做台架测试&#xff0c;VN1600系列的硬件放在架子…

读书笔记:来自一个外企优秀销售的业务心法和秘籍(中)

01 普通销售能达到的三种境界第一 投其所好 &#xff08;110&#xff09;销售把自己的资源1奉献出去&#xff0c;控制不了对方的回报&#xff0c;新人都处在这个阶段。第二 互利互惠 &#xff08;1&#xff0b;1&#xff1d;1&#xff09;大家互相贡献自己的一部分&#xff0c;…

满足你一切需求的 MMYOLO/MMDet 可视化 (一)

可视化在深度学习时代算是核心需求&#xff0c;借助可视化功能&#xff0c;研究者可以快速定位分析模型以及排查问题。在 OpenMMLab 2.0 时代&#xff0c;MMEngine 对常用的可视化需求进行了设计和实现&#xff0c;其具备如下功能&#xff1a; 提供丰富的开箱即用可视化功能&a…

TP6队列与延时队列

安装在此我就不再略过TP6的项目创建过程了&#xff0c;大致就是安装composer工具&#xff0c;安装成功以后&#xff0c;再使用composer去创建项目即可。think-queue 安装composer require topthink/think-queue项目中添加驱动配置我们需要在安装好的config下找到 queue.php<…

Solon v1.12.1 发布,已累计 10000+ 次提交

一个更现代感的 Java 应用开发框架&#xff1a;更快、更小、更自由。没有 Spring&#xff0c;没有 Servlet&#xff0c;没有 JavaEE&#xff1b;独立的轻量生态。主框架仅 0.1 MB。 Controller public class App {public static void main(String[] args) {Solon.start(App.cl…

leetcode刷题精讲————17.电话号码的字母组合

力扣https://leetcode.cn/problems/letter-combinations-of-a-phone-number/description/ 这道题要用到多叉树遍历、回溯、递归、排列组合等相关知识&#xff0c;算是比较经典的例题了&#xff0c;掌握它的核心思想就可以解决这一大类问题。 首先&#xff0c;2~9的数字对应不同…

JS 安全策略 101

依赖审计 依赖审计其实就是利用 npm 或是 yarn 自带的一个 audit 命令检测 node_module 里存在的一些具有安全隐患的依赖项。我习惯用yarn audit, 所以给大家放了张自己博客的 yarn 审计结果。这里显示&#xff1a;一个叫 trim 的包太老了&#xff0c;有很高的安全风险。 有风…

【数据结构初阶】5. 栈和队列

栈 1.1 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。**进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。**栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则…

win7安装onenote2016时碰到30094-1011(0)的 问题

安装办法用途【1】中所有的更新【1】中下载IE11的依赖IE11360软件管家解决OneNote的登录界面不显示问题微软常用运行库360软件管家kernalbase.dll等文件的缺失windowsupdateagent-7.6-x64官网下载Windows6.1-KB4474419-v3-ia64.msu控制面板的update中选择安装支持sha-2校验【3】…

【算法】差分数组

目录1.概述2.代码实现3.应用本文参考&#xff1a; LABULADONG 的算法网站 1.概述 &#xff08;1&#xff09;差分数组的思想与前缀和算法的非常近似&#xff08;有关前置和算法的具体细节可以参考前缀和算法这篇文章&#xff09;&#xff0c;其主要适用于频繁地对原始数组的某…

国产单通道直流有刷马达驱动芯片型号推荐

直流有刷马达驱动芯片是一款适应消费类、工业类的单通道直流有刷驱动IC&#xff0c;适用于各类玩具&#xff0c;智能家居&#xff0c;智能三表。小封装&#xff0c;低功耗&#xff0c;内置完善的保护机制&#xff08;过温/过流/过压&#xff09;。具有一个PWM&#xff08;INA/I…

写了2年文章的我,昨天第一次露脸直播。

作为一名不知名的技术博主&#xff0c;上周六晚上在视频号第一次做露脸直播。 勇敢的迈出视频号开播的第一步&#xff0c;并且数据不错&#xff0c;这个感觉很爽&#xff0c;和写作输出完全是两回事。 写这篇文章的目的是鼓励技术博主们&#xff0c;也尝试一下直播和做视频。 …

ClickHouse 挺快,esProc SPL 更快

开源分析数据库ClickHouse以快著称&#xff0c;真的如此吗&#xff1f;我们通过对比测试来验证一下。 ClickHouse vs Oracle 先用ClickHouse&#xff08;简称CH&#xff09;、Oracle数据库&#xff08;简称ORA&#xff09;一起在相同的软硬件环境下做对比测试。测试基准使用国…

基于ESP8266和SU-03T的离线语音红外遥控器设计

一. 系统设计及框图 之前设计了基于ESP32模块的智能红外遥控器&#xff0c;具体功能见以下CSDN链接&#xff1a; 智能红外遥控器&#xff08;一&#xff09;&#xff1a;功能简介_远望创客学堂的博客-CSDN博客 上面这款智能红外遥控器可以实现红外的远程控制&#xff0c;也可…

【从零开始学习深度学习】44. 图像增广的几种常用方式并使用图像增广训练模型【Pytorch】

大规模数据集是成功应用深度神经网络的前提&#xff0c;图像增广&#xff08;image augmentation&#xff09;技术通过对训练图像做一系列随机改变&#xff0c;来产生相似但又不同的训练样本&#xff0c;从而扩大训练数据集的规模。图像增广的另一种解释是&#xff0c;随机改变…

PCB入门学习—PCB封装的创建2

3.2 IC类PCB封装的创建注&#xff1a;PCB封装的名字一定要和原理图上填写的封装名字一样&#xff0c;不然对不上。规格书里有最大值最小值&#xff0c;就按最大值来做。快捷键EA是特殊粘贴。SOP-8:焊盘比较多时(BGA)可以利用向导去创建。做封装从规格书需要读取的数据&#xff…

19-FreeRTOS 任务通知API

1-xTaskNotifyGive / xTaskNotifyGiveIndexed task.hBaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );BaseType_t xTaskNotifyGiveIndexed( TaskHandle_t xTaskToNotify, UBaseType_t uxIndexToNotify );每个任务都有一组“任务通知” &#xff08;或仅“通知” &a…

Tomcat Connector运行模式

目录 1 Tomcat Connector运行模式 1.1 BIO 模式 1.2 NIO 模式 1.3 APR模式 2 修改Tomcat Connector运行模式为apr 或者解决问题The APR not found 问题 2.1 linux系统 2.2 windows处理 1 Tomcat Connector运行模式 1.1 BIO 模式 BIO模式&#xff08;blocking I/O&am…

[C语言]运用函数指针数组构建一个简单计算器

1.函数指针数组 函数指针数组&#xff0c;即为存放函数首地址的数组&#xff0c;类型为函数指针类型。 2.运用函数指针数组构建简单计算器 1.人机交互&#xff0c;首先要用选择加减或乘除的菜单&#xff0c;再分别写出其功能 void menu() {printf("****************…