博客摘录「 信息学奥赛一本通 1358:中缀表达式值(expr)」2023年11月17日

1. 先判断表达式是否合法括号匹配:

扫描整个算式,遇到左括号就入栈,遇到右括号,就出栈一次。在这一过程中,如果栈空了,还遇到右括号,那么表达式非法。

对于负号:行首的负号,以及'('后的负号,前面插入'0'第一个字符不可以是运算符,除了'('。最后一个字符不可以是运算符,除了')'检查是否有连续出现的运算符()±@如果连续两个字符是运算符:如果两个字符是")(",那么是非法的。

除了上述情况,如果第一个是')',或第二个是'(',那么是合法的。其余两个连续运算符出现的情况全是非法的

2. 中缀表达式转后缀表达式设数组保存后缀表达式

设运算符栈。从左向右扫描表达式字符串:遇到数字时,将数字添加到后缀表达式遇到运算符时入栈

条件为:栈空,或该运算符优先级比栈顶运算符优先级高,或者栈顶是'('。

只有不满足该条件,则一直出栈。

出栈的运算符添加到后缀表达式。扫描结束后若栈中有运算符,都出栈,加入后缀表达式。

可以预先在字符串末尾加上一个优先级最低的')',以促使运算符栈中的运算符都出栈。

不太难,代码见下:

#include<bits/stdc++.h>
using namespace std;
#define N 1005
struct Node
{
    int n;
    char c;
};
Node eq[N];//保存后缀表达式 
int p;
int pri[128];//pri[i]:ascii码为i的运算符的优先级
string s;//中缀表达式字符串 
void initPri()
{
    pri['('] = 4;
    pri['*'] = pri['/'] = 3;
    pri['+'] = pri['-'] = 2;
    pri[')'] = 1;
} 
int calc(int a, int b, char c) 
{
	switch(c)
	{
		case '+':
			return a+b;
		case '-':
			return a-b;
		case '*':
			return a*b;
		case '/':
			return a/b;
	}	
}
bool isCalc(char c)//判断c是否是运算符
{
    return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
} 
bool isValid()//判断s是否是合法的中缀表达式 
{
    //1.检查括号匹配 
    stack<char> stk;
    for(int i = 0; i < s.length(); ++i) 
    {
        if(s[i] == '(')
            stk.push(s[i]);
        else if(s[i] == ')')
        {
            if(stk.empty())
                return false;
            else
                stk.pop();
        }
    }
    if(stk.empty() == false)
        return false;
    //2.单独的负号前加0 
    for(int i = 0; i < s.length(); ++i)
    {
        if(i == 0 && s[i] == '-')
            s = '0' + s;//前面加0
        else if(s[i] == '-' && s[i-1] == '(')//右括号后面的负号
            s.insert(i, "0");//在第i位置插入0 
    }
    //3. 除了首位的'('与末尾的')',其余情况首尾不能为运算符
    if(isCalc(s[0]) && s[0] != '(')
        return false;
    int ed = s.length()-1;//末尾位置下标 
    if(isCalc(s[ed]) && s[ed] != ')')
        return false;
    //4.判断是否有连续的不合法的运算符
    for(int i = 0; i < s.length()-1; ++i)
    {
        if(isCalc(s[i]) && isCalc(s[i+1]))//如果有相邻两个运算符
        {
            if(s[i] == ')' && s[i+1] == '(')
                return false;
            else if(!(s[i] == ')' || s[i+1] == '('))//如果第一个是'')'',或第二个是''('',那么是合法的。其余是非法的。 
                return false;
        }       
    } 
    return true;
}
int solve()//递归求解后缀表达式 
{
    int i = p--;
    if(eq[i].c)
    {
        int b = solve(); 
        int a = solve();
        return calc(a, b, eq[i].c);
    }
    else
        return eq[i].n;
}
int main()
{
    initPri();//初始化pri数组 
	int n, num = 0;
	cin >> s;
	if(isValid() == false)
	{
	    cout << "NO";
	    return 0;
    }
	s += ')';//取巧,把一个优先级最低的符号')'加到字符串末尾,促使运算符都出栈,以完成最后的计算。 
	stack<char> cStk;//运算符栈 
	bool isFormingNum = false;//标志位 表示是否正在构造数字 
	for(int i = 0; i < s.length(); ++i)//最后一次取到人为添加的')' 
	{
		if(s[i] >= '0' && s[i] <= '9')//如果扫描到数字 
		{
			isFormingNum = true;
			num = num * 10 + s[i] - '0';//将字符串转化为数 
		}
		else//如果扫描到运算符 
		{
			if(isFormingNum)//如果正在构造数字 
			{
			    eq[++p].n = num;//将构造好的数字加入后缀表达式 
				num = 0;//保存数字的变量复原
				isFormingNum = false;
			}
			while(!(cStk.empty() || pri[s[i]] > pri[cStk.top()] || cStk.top() == '('))//入栈条件:栈空或要入栈的运算符比栈顶的优先级更高或栈顶为左括号。入栈条件取反就是出栈条件。 
			{
			    eq[++p].c = cStk.top(); 
                cStk.pop();
			}
			if(cStk.empty() == false && cStk.top() == '(' && s[i] == ')')//如果左右括号配对 
				cStk.pop();//弹出左括号 不压栈 
			else 
				cStk.push(s[i]);//运算符压栈 
		}
	}
	cout << solve();//求后缀表达式eq的值 
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值