用逆波兰表达式制作一个简易的计算器(中缀表达式转后缀表达式)

介绍

最近在学习c++的数据结构时,学到对表达式的求值,正好又看到一个比较基础的c++程序设计题目,即设计一个简易的计算器
首先我们求一个表达式的值时用的是中缀表达式,例如求3 + 6 / 2的值时,我们会先计算6/2的值然后在计算加法,但是在计算机中并不会这么聪明的知道计算的优先级,因此我们需要将表达式转换称为计算机能理解的表达式,这里就涉及到数据结构中的中缀表达式转后缀表达式。

中缀表达式转后缀表达式

规则

中缀表达式a + b*c + (d * e + f) * g,其转换成后缀表达式则为a b c * + d e * f + g * +。

转换过程需要用到栈,具体过程如下:

1)如果遇到操作数,我们就将操作数作为数字字符保存。

2)如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。

3)如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。

4)如果遇到任何其他的操作符,如(“+”, “*”,“(”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。有一点需要注意,只有在遇到" ) “的情况下我们才弹出” ( “,其他情况我们都不会弹出” ( "。

5)如果我们读到了输入的末尾,则将栈中所有元素依次弹出。
具体看看代码的实现。

代码

我们首先定义运算符的优先级

int priority(char a)
{
	int temp;
	if (a=='*' || a=='/')
	{
		temp = 2;
	}
	if (a=='+' || a=='-')
	{
		temp = 1;
	}
	return temp;
}

定义完优先级之后就确定输出的字符是数字还是操作符。

bool isOperator(char ch)
{
	switch (ch)
	{
		case '+' : case '-' : case '*' : case '/' :
			return true;
		default:
			return false;
	}
}

有了上面两个函数之后就可以开始对中缀表达式进行转换了:

string getPostfixExp(string& infix)
{
	stack<char> operator_stack;
	string postfix;
	for (auto p : infix)
	{
		if (isOperator(p))
		{
			while (!operator_stack.empty() && isOperator(operator_stack.top()) && priority(operator_stack.top()) >= priority(p))//当栈里面有操作符之后进行一些列的判断
			{
				postfix.push_back(operator_stack.top());
				postfix.push_back(' ');
				operator_stack.pop();
			}
			operator_stack.push(p);//当首先栈里面没有操作符时将字符串里面的操作符添加进去
		}
		else if (p == '(')
		{
			operator_sack.push(p);
		}
		else if (p == ')')
		{
			while (operator_stack.top() != '(')
			{
				postfix.push_back(operator_stack.top());
                postfix.push_back(' ');
                operator_stack.pop();
			}
		}
		else  //代表字符为数字字符
		{
			postfix.push_back(p);
			postfix.push_back(' ');
		}
		
		//当遍历到中缀表达式中的最后一个数字字符时,操作符栈里面还剩一个操作符未能进行添加,因此
		 while (!operator_stack.empty())
       {
       		postfix.push_back(operator_stack.top());
       		postfix.push_back(' ');
        	operator_stack.pop();
       }
        postfix.pop_back();//删除后缀表达式中的最后一个空字符
        return postfix;
	}
}

经过上面的操作之后就可以利用后缀表达式进行计算啦!

int postfixCalculate(string& postfix)
{
    int first, second;
    stack<int> num_stack;
    for (auto p : postfix)
    {
        switch (p)
        {
            case '*':
                first = num_stack.top();
                num_stack.pop();
                second = num_stack.top();
                num_stack.pop();
                num_stack.push(first * second);
                break;
            case '/':
                first = num_stack.top();
                num_stack.pop();
                second = num_stack.top();
                if (first == 0)
                {
                    cout<<"divide by zero";
                    break;
                }
                else
                {
                    num_stack.pop();
                    num_stack.push(first / second);
                    break;
                }
                
            case '+':
                first = num_stack.top();
                num_stack.pop();
                second = num_stack.top();
                num_stack.pop();
                num_stack.push(first + second);
                break;
            case '-':
                first = num_stack.top();
                num_stack.pop();
                second = num_stack.top();
                num_stack.pop();
                num_stack.push(first - second);
                break;
            case ' ':
                break;
                //if the item is a number then push it in the stack
            default:
                num_stack.push(p - '0'); //数字字符减去'0'就得到了该数字
                break;
        }
    }
    int result = num_stack.top();
    num_stack.pop();
    return result;
}

下面贴出整个完整的代码:

#include<iostream>
#include<string>
#include<stack>
#include<iomanip>


using namespace std;

bool isOperator(char ch);
int priority(char a);

string getPostfixExp(string& infix)
{
    stack<char> operator_stack;
    string postfix;
    for (auto p : infix)
    {
        if (isOperator(p))
        {
            while (!operator_stack.empty() && isOperator(operator_stack.top()) && priority(operator_stack.top()) >= priority(p))
            {
                postfix.push_back(operator_stack.top());
                postfix.push_back(' ');
                operator_stack.pop();
            }
            operator_stack.push(p);
        }
        else if (p == '(')
        {
            operator_stack.push(p);
        }
        else if (p == ')')
        {
            while (operator_stack.top() != '(')
            {
                postfix.push_back(operator_stack.top());
                postfix.push_back(' ');
                operator_stack.pop();
            }
            operator_stack.pop();
        }
        else
        {
            postfix.push_back(p);
            postfix.push_back(' ');
        }
        
    }
    while (!operator_stack.empty())
    {
        postfix.push_back(operator_stack.top());
        postfix.push_back(' ');
        operator_stack.pop();
    }
    postfix.pop_back();
    return postfix;
}

bool isOperator(char ch)
{
    switch(ch)
    {
        case '+': case '-': case '*': case '/':
            return true;
        default:
            return false;
    }
}

int priority(char a)
{
    int temp;
    if (a == '*' || a == '/')
        temp = 2;
    else if (a == '+' || a == '-')
        temp = 1;
    return temp;
}

//得到了后缀表达式,可以开始求值
int postfixCalculate(string& postfix)
{
    int first, second;
    stack<int> num_stack;
    for (auto p : postfix)
    {
        switch (p)
        {
            case '*':
                first = num_stack.top();
                num_stack.pop();
                second = num_stack.top();
                num_stack.pop();
                num_stack.push(first * second);
                break;
            case '/':
                first = num_stack.top();
                num_stack.pop();
                second = num_stack.top();
                if (first == 0)
                {
                    cout<<"divide by zero";
                    break;
                }
                else
                {
                    num_stack.pop();
                    num_stack.push(first / second);
                    break;
                }
                
            case '+':
                first = num_stack.top();
                num_stack.pop();
                second = num_stack.top();
                num_stack.pop();
                num_stack.push(first + second);
                break;
            case '-':
                first = num_stack.top();
                num_stack.pop();
                second = num_stack.top();
                num_stack.pop();
                num_stack.push(first - second);
                break;
            case ' ':
                break;
                //if the item is a number then push it in the stack
            default:
                num_stack.push(p - '0'); //数字字符减去'0'就得到了该数字
                break;
        }
    }
    int result = num_stack.top();
    num_stack.pop();
    return result;
}

int main()
{
    string infix;
    cin>>infix;
    string postfix = getPostfixExp(infix);
    cout<<postfix<<endl;
    cout<<postfixCalculate(postfix)<<endl;
    return 0;
}

上面代码的逻辑很清晰,耐心看完应该不难。
理论知识参考b栈里面的一个视频:中缀表达式转后缀表达式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值