支持多种运算符的字符串表达式求值

冷暖自知 提交于 2020-01-30 08:39:04

一、说明

1. 输入字符串为中缀表达式,无需转为后缀表达式

2. 支持的运算符包括:

算术运算符:"+,-,*,/"

关系运算符:">,<,>=,<=,=,!="(注意等于运算符采用的是一个等号)

逻辑运算符:"&&,||"

3. 支持大于10的数字,不支持负数操作数,但支持中间结果和返回值为负数

二、算法原理&步骤

本文算法对中缀表达式形式字符串进行求值,同时支持与或运算和逻辑运算(若含有关系运算符或者逻辑运算符,则输出为1或者0)。类似于加减乘除,将关系运算符和逻辑运算符看作优先级低的运算符进行处理,优先级:算术运算符>关系运算符>逻辑运算符。

步骤:

1. 初始化两个空堆栈,一个存放操作数,一个存放运算符。

2. 从左至右扫描输入字符串,依次读取。

  • 2.1 若为操作数,则压入操作数栈;
  • 2.2 若为运算符,判断其优先级是否大于运算符栈栈顶元素优先级。若大于栈顶元素优先级,则直接压栈;否则,弹出栈顶元素operator,同时依次从操作数栈中弹出两个元素number1,number2,计算表达式(number2 operator number1)的值value,并将值value压入操作数栈。重复上述过程直至当前扫描的操作符优先级大于栈顶元素,然后将当前运算符压栈。

3. 弹出运算符栈顶元素operator,同时依次从操作数栈中弹出两个元素number1,number2,计算表达式(number2 operator number1)的值value,并将值value压入操作数栈。重复上述过程直至运算符栈为空。

4. 此时操作数栈应该只有一个元素,即为表达式的值。

三、代码&测试

求值函数:

/* 字符串表达式求值
 * @param input: 输入的字符串
 * @param output: 表达式的值,若含有关系运算符则为1或者0
 * return 计算过程是否正常
 */
bool ExpValue(string input,int& output)
{
	stack<int> operand_stack;
	stack<string> operator_stack;

	char prev = 0; // 上一个属于运算符的字符
	for (int i = 0; i < input.size(); i++)
	{
		char c = input[i];
		// prev是否是一个完整运算符
		if (!isOperator(c) && prev)
		{
			string new_op = string("").append(1, prev);
			addNewOperator(new_op, operand_stack, operator_stack);
			prev = 0;
		}

		// 数字
		if (isdigit(c))
		{
			int val_c = c - '0';
			if (i > 0 && isdigit(input[i - 1]))
			{
				int top_num = operand_stack.top();
				top_num = top_num * 10 + val_c;
				operand_stack.pop();
				operand_stack.push(top_num);
			}
			else
				operand_stack.push(val_c);
		}
		// 运算符字符
		else if (isOperator(c))
		{
			// 处理两字符运算符
			if (prev)
			{
				string new_op = string("").append(1, prev).append(1, c);
				addNewOperator(new_op, operand_stack, operator_stack);
				prev = 0;
			}
			else
				prev = c;
		}
		else if (c == '(')
			operator_stack.push("(");
		else if (c == ')')
		{
			// 处理括号内的运算符
			while (operator_stack.top()!="(")
			{
				int num1 = operand_stack.top();
				operand_stack.pop();
				int num2 = operand_stack.top();
				operand_stack.pop();
				string op = operator_stack.top();
				operator_stack.pop();

				int val = Calculate(num2, num1, op);
				operand_stack.push(val);
			}
			operator_stack.pop(); // 弹出"("
		}
	}
	assert(operand_stack.size() == operator_stack.size() + 1);
	// 弹出所有运算符
	while(!operator_stack.empty())
	{
		int num2 = operand_stack.top();
		operand_stack.pop();
		int num1 = operand_stack.top();
		operand_stack.pop();
		string op = operator_stack.top();
		operator_stack.pop();

		int val = Calculate(num1, num2, op);
		operand_stack.push(val);
	}

	if (operand_stack.size() == 1) {
		output = operand_stack.top();
		return true;
	}
	return false;
}

其中用到的子函数有:

/* 判断字符是否属于运算符 */
bool isOperator(char c)
{
	switch (c)
	{
	case '-':
	case '+':
	case '*':
	case '/':
	case '%':
	case '<':
	case '>':
	case '=':
	case '!':
	case '&':
	case '|':
		return true;
	default:
		return false;
	}
}

/* 获取运算符优先级 */
int getPriority(string op)
{
	int temp = 0;
	if (op == "*" || op == "/" || op == "%")
		temp = 4;
	else if (op == "+" || op == "-")
		temp = 3;
	else if (op == ">" || op == "<" || op == ">=" || op == "<="
		|| op == "=" || op == "!=")
		temp = 2;
	else if (op == "&&" || op == "||")
		temp = 1;
	return temp;
}
/* 
 * 返回一个两元中缀表达式的值
 * syntax: num_front op num_back
 * @param num_front: 前操作数
 * @param num_back: 后操作数
 * @param op: 运算符
 */
int Calculate(int num_front, int num_back, string op)
{
	if (op == "+")
		return num_front + num_back;
	else if (op == "-")
		return num_front - num_back;
	else if (op == "*")
		return num_front * num_back;
	else if (op == "/")
		return num_front / num_back;
	else if (op == "%")
		return num_front % num_back;
	else if (op == "!=")
		return num_front != num_back;
	else if (op == ">=")
		return num_front >= num_back;
	else if (op == "<=")
		return num_front <= num_back;
	else if (op == "=")
		return num_front == num_back;
	else if (op == ">")
		return num_front > num_back;
	else if (op == "<")
		return num_front < num_back;
	else if (op == "&&")
		return num_front && num_back;
	else if (op == "||")
		return num_front || num_back;

	return 0;
}
/* 新运算符入栈操作 */
void addNewOperator(string new_op, stack<int>& operand_stack, stack<string>& operator_stack)
{
	while (!operator_stack.empty() && getPriority(operator_stack.top()) >= getPriority(new_op))
	{
		int num2 = operand_stack.top();
		operand_stack.pop();
		int num1 = operand_stack.top();
		operand_stack.pop();
		string op = operator_stack.top();
		operator_stack.pop();

		int val = Calculate(num1, num2, op);
		operand_stack.push(val);
	}
	operator_stack.push(new_op);
}

测试: 

int main()
{
	string s0 = "10-1*10+3%2";
	string s1 = "100 + (3-33)*2";
	string s2 = "20+1 >= 20 && 20+1 < 20";
	string s3 = "10>20 || 10/1>=5";
	int ret = -1;
	if (ExpValue(s0, ret))
		cout << s0 << "的值: " << ret << endl;

	if (ExpValue(s1, ret))
		cout << s1 << "的值: " << ret << endl;

	if (ExpValue(s2, ret))
		cout << s2 << "的值: " << ret << endl;

	if (ExpValue(s3, ret))
		cout << s3 << "的值: " << ret << endl;
	return 0;
}

上述代码的执行结果为:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!