数据结构 C 代码 3.3: 栈的应用 -- 表达式求值

摘要: 表达式求值看起来比较复杂, 居然用两个栈就可以实现.

1. 代码

先上代码, 再讲废话. 注意, 现在这一版代码是 2020 级刘知鑫同学写的, 用了面向对象. 工具比较高档, unordered_map 这些我都没听说过.

//202031061018 刘知鑫
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <unordered_map>

using namespace std;

stack<int> num;
stack<char> op;

void eval()
{
    auto b = num.top();
    num.pop();
    auto a = num.top();
    num.pop();
    auto c = op.top();
    op.pop();
    int x;
    if (c == '+') x = a + b;
    else if (c == '-') x = a - b;
    else if (c == '*') x = a * b;
    else x = a / b;
    num.push(x);
}

int main()
{
    unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
    string str;
    cin >> str;
    for (int i = 0; i < str.size(); i ++ )
    {
        auto c = str[i];
        if (isdigit(c))
        {
            int x = 0, j = i;
            while (j < str.size() && isdigit(str[j]))
                x = x * 10 + str[j ++ ] - '0';
            i = j - 1;
            num.push(x);
        }
        else if (c == '(') op.push(c);
        else if (c == ')')
        {
            while (op.top() != '(') eval();
            op.pop();
        }
        else
        {
            while (op.size() && op.top() != '(' && pr[op.top()] >= pr[c]) eval();
            op.push(c);
        }
    }
    while (op.size()) eval();
    cout << num.top() << endl;
    return 0;
}

2. 代码说明

  1. 把字符串写的表达式求值.
  2. 考虑基本的加减乘除运算.
  3. 需要为操作数与操作符分别建栈.
  4. 需要在稍高版本的环境运行.
  5. 我准备找时间把它改成比较基础的版本.

3. 支持小数

邓钦的版本.

#include <iostream>
#include <unordered_map>
#include <cstring>
#include <stack>
#include <stdio.h>

using namespace std;


/*定义全局栈*/
stack<double> num;//数据栈
stack<char> op;//运算符栈


void arithmetic()
{
	auto first_num = num.top();//取出栈顶元素
	num.pop();//更新栈顶元素
	auto second_num = num.top();//取出第二个栈顶元素
	num.pop();//更新栈顶

	auto operation_symbol = op.top();//取出栈顶运算符
	op.pop();

	double sum = 0;

	switch (operation_symbol)
	{
		case '+':
			sum = second_num + first_num;
			break;
		case '-':
			sum = second_num - first_num;
			break;
		case '*':
			sum = second_num * first_num;
			break;
		case '/' :
			sum = second_num / first_num;
			break;
		default:
			break;
	}
	num.push(sum);
}


void Test()
{
	//运算符容器。‘+’对应数字1,类似于ASCII码值的对应
	unordered_map<char, int> Operator
	{
		{'+',1},{'-',1},{'*',2},{'/',2}
	};

	string str;
	cout << "请输入表达式   (负数表示为:(0-a))" << endl;
	cin >> str;
	int flag = 1;//负数的处理

	for (int i = 0; i < str.size(); i++)
	{
		auto c = str[i];
		if (isdigit(c))
		{
			double data = 0;
			int j = i;
			while (j < str.size() && isdigit(str[j])&&str[j]!='.')
			{
				data = data * 10 + str[j++] - '0';//由于定义输入的是string类型,涉及到强制转换,数字字符减去‘0’,
												//经过ASCII码值的转换就是对应的十进制数字
			}

			if (str[j] == '.')
			{
				j++;
				int power = -1;
				while (isdigit(str[j]))
				{
					data = data + (str[j] - '0') * pow(10,power);
					j++;
					power--;
				}
					
			}
			i = j-1;//退出循环,说明j下标对应的不是数字了,退一位,是因为i在for循环要i++,无次-1操作就会出现,i的两次跳跃

			num.push(data*flag);
			flag = 1;
		}
		else if (c == '(')
		{
			op.push(c);

			if (str[i + 1] == '-')
			{
				flag = -1;
				i++;
			}
			else
				flag = 1;

		}
		else if (c == ')')
		{
			while (op.top() != '(')//进入该循环是在处理括号内部的计算
			{
				arithmetic();
			}
			op.pop();
		}
		else//运算符压栈
		{
			if (c != '+' && c != '-' && c != '*' && c != '/')
			{
				cout << "非法输入!!!"<<endl;
				return;
			}
			while (op.size() && op.top() != '(' && Operator[op.top()] >= Operator[c])
			{
				arithmetic();
			}
			op.push(c);
		}
		
	}

	while (op.size())//只要还有运算符就说明没有结束运算
	{
		arithmetic();
	}

	cout <<"结果为:"<< num.top() << endl<<endl;
}
int main()
{
	Test();
	system("pause");
	return 0;
}


欢迎留言.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值