Leetcode -calculator 总结

中缀表达式求值是非常经典的题目,主要考察stack的使用,本文主要介绍如何使用stack解决中缀表达式求值(包含±*/与括号)的问题。

解题思路

设置两个stack,分别用来存储操作数与操作符,我们分别称之为op_num与op_ch。
接下来就是遍历表达式啦:

  1. 如果遇到了数字,那就把数字整个取出来,放到op_num中
  2. 如果遇到了空格,跳过就好了
  3. 如果遇到了操作符,那就看操作符op的优先级:
    1. 如果比栈顶的运算符优先级低,那就压入栈中
    2. 如果比栈顶的运算符优先级相等或者高,那么就取出两个操作数与一个运算符,运算后把结果放入op_num中(这里注意取出的运算数依次为a和b,那么运算的时候顺序要反过来: b 运算符 a),重复此过程,直到栈顶运算符优先级比运算符op低,把op压入栈。
  4. 遍历完后,如果栈不为空,那么不断去除运算符与操作数,不断运算,如果表达式是正常合法的,那么当op_ch空的时候,op_num应该只剩下一个结果,就是最终的表达式运算结果。

TIPS: 建议事先在op_ch中压入一个特殊的运算符,比如’.’,并定义它的优先级为最低,这样在上面的第三步就不用判断栈op_ch是否为空了,只要判断op的优先级与栈顶的运算符优先级的关系就好了。

TIPS:建议事先在字符串后面加上一个空格,不影响运算,但是在从表达式里面取出操作数时,可以避免判断下标是否越界。(主要针对以下这种取出操作数的方式)

if (s[i] >= '0' && s[i] <= '9') {
	// number
	int number = 0;
	int p = i;
	while (s[p] >= '0' && s[p] <= '9') {   
	//如果遇到最后一个字符是数字的时候,有可能因为越界造成危险,
 	// c++ stl的string越界不会返回错误
		number = number * 10 + (s[p] - '0');
		p++;
	}
	i = p - 1;
	op_num.push(number);
	continue;
}

遇到括号怎么办呢?

定义左括号的优先级为最低,这么做是为了在上面的第三步中比较断op的优先级与栈顶的运算符优先级的关系时不会受到左括号的影响,继续阅读可以更深入地理解这一点。

  • 如果遇到了左括号,不说别的,直接压入栈op_ch就好了
  • 如果遇到了右括号,不断取出操作数与运算符进行计算,直到遇到了左括号,把左括号从栈里取出来,什么也不干,继续遍历就好了。

附上Basic Calculator的代码,针对Basic Calculator和Basic Calculator II

int get_priority(char op) {
	switch (op)
	{
	case '+':
	case '-':
		return 1;
	case '*':
	case '/':
		return 2;
	case '(':
	case '.': 
		return 0;
	default:
		return -1;
	}
}

// we need a simple calculator
int calculate(string s) {
	int slength = s.length();
	if (slength == 0)
		return 0;
	s.push_back(' ');
	// normal case
	stack<char> op_ch;
	op_ch.push('.');
	stack<int> op_num;
	int re = 0;
	for (int i = 0; i < slength; i++) {
		//cout << s[i] << endl;
		// start calculate
		if (s[i] == ' ')
			continue;
		if (s[i] >= '0' && s[i] <= '9') {
			// number
			int number = 0;
			int p = i;
			while (s[p] >= '0' && s[p] <= '9') {
				number = number * 10 + (s[p] - '0');
				p++;
			}
			i = p - 1;
			op_num.push(number);
			continue;
		}
		// operator
		if (s[i] == '(') {
			op_ch.push(s[i]);
			continue;
		}
		else if (s[i] == ')') {
			while (op_ch.top() != '(') {
				int b = op_num.top();
				op_num.pop();
				int a = op_num.top();
				op_num.pop();

				switch (op_ch.top()) {
				case '+':
					op_num.push(a + b);
					break;
				case '-':
					op_num.push(a - b);
					break;
				case '*':
					op_num.push(a * b);
					break;
				case '/':
					op_num.push(a / b);
					break;

				}
				op_ch.pop();
			}
			op_ch.pop();
			continue;
		}
		int prior = get_priority(s[i]);
		if (get_priority(op_ch.top()) < prior) {
			op_ch.push(s[i]);
			continue;
		}
		while (get_priority(op_ch.top()) >= prior) {
			int b = op_num.top();
			op_num.pop();
			int a = op_num.top();
			op_num.pop();

			switch(op_ch.top()) {
			case '+':
				op_num.push(a + b);
				break;
			case '-':
				op_num.push(a - b);
				break;
			case '*':
				op_num.push(a * b);
				break;
			case '/':
				op_num.push(a / b);
				break;

			}
			op_ch.pop();
		}
		op_ch.push(s[i]);
	}

	while (op_ch.top() != '.') {
		int b = op_num.top();
		op_num.pop();
		int a = op_num.top();
		op_num.pop();

		switch (op_ch.top()) {
		case '+':
			op_num.push(a + b);
			break;
		case '-':
			op_num.push(a - b);
			break;
		case '*':
			op_num.push(a * b);
			break;
		case '/':
			op_num.push(a / b);
			break;

		}
		op_ch.pop();
	}
	cout << op_num.size() << endl;
	return op_num.top();
}

你可能感兴趣的:(C++)