算法第四版- 1.3 背包、队列和栈-Dijkstra的双栈算术表达式求值

算法第四版- 1.3 背包、队列和栈

Dijkstra的双栈算术表达式求值

1.课本代码

先贴课本上的测试代码,java转C++

#include <iostream>
#include <vector>
#include <stack>
using namespace std;
double Evaluate(char* a)
{
	stack<char> ops;// 存字符
	stack<double>vals; //存数字
	int i = 0;
	double ans = 0;
	double v, v1;
	char op;
	while (a[i] != '\0')
	{
		switch (a[i])
		{
		case '(':
			break;
		case '+':
		case '-':
		case '*':
		case '/':
			ops.push(a[i]);
			break;
		case ')':
			op = ops.top();
			ops.pop();
			
			v = vals.top();
			vals.pop();
			
			v1 = vals.top();
			vals.pop();
			
			switch (op)
			{
			case '+':
				v = v1 + v;
				break;
			case '-':
				v = v1 - v;
				break;
			case '*':
				v = v1 * v;
				break;
			case '/':
				v = v1 / v;
				break;
			}
			vals.push(v);
			break;
		default:
			vals.push(double(a[i])-48);
		    //字符与数字之间ASCII码的转换,bug找了好久。

		}
		i++;
	}
	ans=vals.top();
	vals.pop();
	return ans;
}
//如果中间有sqrt,该如何读进去呢。应该是读到s然后再多读三个字母。不再赘余
//如果不是各位数呢,判断下一位是不是数字,如果是,*10再加上
int main()
{
	char a[20] = "(1+((2+3)*(4*5)))";
	cout<<Evaluate(a);
	return 0;
}

书上写的四种情况很清楚:
1.将操作数压入操作数栈
2.将运算符压入运算符栈
3.忽略左括号
4.当遇到右括号时,弹出一个运算符,弹出所需数量的操作数,并将运算符和操作数的运算结果压入操作数栈。

2.lc第150题,逆波兰表达式

当然,也可以用一个栈去做。
首先先来看一下逆波兰表达式。力扣150题
输入:tokens = [“4”,“13”,“5”,"/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> stk;
        int n = tokens.size();
        for (int i = 0; i < n; i++) {
            string& token = tokens[i];
            if (isNumber(token)) {
                stk.push(atoi(token.c_str()));
            } else {
                int num2 = stk.top();
                stk.pop();
                int num1 = stk.top();
                stk.pop();
                switch (token[0]) {
                    case '+':
                        stk.push(num1 + num2);
                        break;
                    case '-':
                        stk.push(num1 - num2);
                        break;
                    case '*':
                        stk.push(num1 * num2);
                        break;
                    case '/':
                        stk.push(num1 / num2);
                        break;
                }
            }
        }
        return stk.top();
    }

    bool isNumber(string& token) {
        return !(token == "+" || token == "-" || token == "*" || token == "/");
    }
};

这个题用string类型,解决了13这种不是个位数的问题。很好,也是原书java中用的方法。
然后中缀转后缀,再看别的博客吧。

然后是第224题和第227题

3.lc第224题

第224题,只有加减和括号,没有乘除
则,我们可以把所有的括号拆开
比如1-(2+3) = 1-2-3

class Solution {
public:
    int calculate(string s) {
        stack<int> ops;
        ops.push(1);
        int sign = 1;
        //sign是1表示是+号,sign是-1表示是负号

        int ret = 0;
        int n = s.length();
        int i = 0;
        while (i < n) {
            if (s[i] == ' ') {
                i++;
            } else if (s[i] == '+') {
                sign = ops.top();
                i++;
            } else if (s[i] == '-') {
                sign = -ops.top();
                i++;
            } else if (s[i] == '(') {
                ops.push(sign);
                i++;
            } else if (s[i] == ')') {
                ops.pop();
                i++;
            } else {
                long num = 0;
                while (i < n && s[i] >= '0' && s[i] <= '9') {
                    num = num * 10 + s[i] - '0';
                    i++;
                }//这里解决了非个位数的问题
                ret += sign * num;
            }
        }
        return ret;
    }
};

4.lc第227题

只有±*/,没有括号
如果有括号,还是用课本上两个栈的好
摘录:
一般需要符号栈、数据栈,两个。但是,看到网上一个写的不错的算法,只用了一个数据栈。符号栈用一个变量sign代替了,只存储上一个符号,主要思想如下:

1.将减法转化为加法(取相反数)

2.由于乘除法优先级高,直接计算

3.整数不仅一位,会>10

4.表达式中没有括号

class Solution {
public:
    int calculate(string s) {
        vector<int> stk;
        char preSign = '+';
        int num = 0;
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            if (isdigit(s[i])) {
                num = num * 10 + int(s[i] - '0');
            }
            if (!isdigit(s[i]) && s[i] != ' ' || i == n - 1) {
                switch (preSign) {
                    case '+':
                        stk.push_back(num);
                        break;
                    case '-':
                        stk.push_back(-num);
                        break;
                    case '*':
                        stk.back() *= num;
                        break;
                    default:
                        stk.back() /= num;
                }
                preSign = s[i];
                num = 0;
            }
        }
        return accumulate(stk.begin(), stk.end(), 0);

    }
};

相当于把所有数都压进去,最后累加。
不过压进去之前,* /要先算好,- 也要搞好。
比如"3 + 2*2",压进去就是3,4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值