简单计算机——逆波兰表达式

Posted Hunter丶安

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单计算机——逆波兰表达式相关的知识,希望对你有一定的参考价值。

逆波兰数:逆波兰数由两部分组成(操作数,操作符)——是波兰表达式的一种,即操作符在操作数的后面。

形式:A+B*C-D = ABC*D-;

   (A+B)*C-D = AB+C*D-;

既然我们知道了,后缀表达式那我们表达式是唯一的吗?我们来看一组数据:

例如:(A+B)*C-D 和 C*(A+B)-D;

很显然第二个的表达式为:C*AB+D-;虽然对最后的结果无影响,但我们需要知道逆波兰的多样性。

 

注意事项:

1、如果出现1+23 = 123+,该如何判断它的数值呢?

  可以利用分割符来进行很好的辅助性理解,例如1+23 = 1#23#+,这样可以完美的解决此问题。

2、存在括号的时候该如何处理?

  其一:是‘(’直接压入,‘)’时,将两者之间的运算符弹出,压入后缀表达式。

  其二:遇到‘(’开辟一个新的运算符栈,‘)’时,当前栈内运算符弹出,压入后缀表达式。

 

算法:

1、中缀表达式——逆波兰表达式的转变。

  • 准备一个栈一个链表,链表用来存操作数,栈用来存操作符。
  • 如果为操作数,我们继续判断它的下一位是否也为操作数,是——则继续压入,否——压入分隔符(“#”)。同时判断字符栈中,是否为“*”,“/”,字符弹出,压入数值链表。
  • 如果为操作符,直接压入字符栈。
  • 如果‘(’,重新开辟一个新字符栈,其它操作相同。
  • 如果‘ )’,将当前字符栈内部的字符逐个弹出,压入数值链表。

2、逆波兰求值。

  • 准备一个栈,用来逐个求当前值。
  • 依次取出数值链表的第一个值。
  • 根据加减乘除运算做出相应的操作,即取出当前栈的前两个值,做运算符操作。
  • 如果是操作数,我们继续判断它的下一位是否也为操作数,是——n*10+char-‘0’,否——压入栈中;
  • 最后的到栈顶元素,即为运算后的值。

核心代码:

1、中缀表达式——逆波兰表达式的转变。

技术分享
bool is_char(char c)//判断是否为操作符
{
    return c == - || c == + || c == * || c == /;
}

void change()//表达式的转化
{
    char c;
    int i = 0, j = 0;//i遍历输入的字符,j不同层数的字符栈
    while ((c = original[i++]) != \0)
    {
        if (is_char(c))//是字符
            one[j].push(c);
        else if (is_number(c))//是数字
        {
            int x = i;//
            while (is_number(c))
            {
                sconed.push_back(c);
                if (is_number(c = original[x++]))//是数值,则数组往后移动一位(确保下一步能读取字符)
                    i++;
            }
            sconed.push_back(#);//分隔符
            if (!one[j].empty())//判断是否为空
                if (one[j].top() == * || one[j].top() == /)//高阶运算,直接取出,压入数值链表
                {
                    sconed.push_back(one[j].top());
                    one[j].pop();
                }
        }
        else if (c == ))
        {
            Dum(j);//多余的运算符赋值
            j--;//回到上一层的字符栈
        }
        else
            j++;//新的字符栈
    }
    Dum(j);
}

void Dum(int j)//多余的运算符逐个压入数值链表
{
    while (!one[j].empty())
    {
        sconed.push_back(one[j].top());
        one[j].pop();
    }
}
View Code

2逆波兰求值。

技术分享
void Do_it(std::stack<int> &mc)
{
    while (!sconed.empty())//不为空时。
    {
        char mid = sconed.front();//临时存储字符
        sconed.pop_front();//压出
        switch (mid)//判断
        {
            int a, b;
        case-:
            b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前两个数值进行减法运算。
            mc.push(a - b);
            break;
        case+:
            b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前两个数值进行加法运算。
            mc.push(a + b);
            break;
        case*:
            b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前两个数值进行乘法运算。
            mc.push(a * b);
            break;
        case/:
            b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前两个数值进行除法运算。
            if (b == 0)//分母不能位0
            {
                is_right = false;
                return;
            }
            else
                mc.push(a / b);
            break;
        default://获得数值
        {
            int sum = 0;
            if (is_number(mid))
            {
                while (is_number(mid))
                {
                    sum = sum * 10 + mid - 0;//字符到数字的改变
                    mid = sconed.front();
                    if (is_number(mid))
                        sconed.pop_front();
                }
                mc.push(sum);
            }
        }
        }
    }
}
Do_it

3、GitHub源码;

 

 

 



以上是关于简单计算机——逆波兰表达式的主要内容,如果未能解决你的问题,请参考以下文章

粗浅看 逆波兰式算法

Java代码实现逆波兰计算器

python实现逆波兰计算表达式的代码

逆波兰计算器

逆波兰计算器

算法与数据结构--栈的应用-逆波兰计算器完整版代码