数据结构学习之栈-逆波兰表达式(一)

  • 其实逆波兰表达式不难,更是栈的一个经典问题。网上关于逆波兰表达式的blog也很多。本人也曾经受到这些好blog的帮助。只不过,别人做过的事,毕竟不是自己做过的。因此,为了一步一步脚踏实地。我也写一篇blog来讲讲逆波兰表达式核心思路。
  • 逆波兰表达式主要是两个部分:1、中缀转后缀。2、后缀表达式求值
  • 中缀表达式,后缀表达式这些名词可能对于菜鸟程序员来说,是个新鲜的词语。中缀表达式就是我们生活中经常写的“1+2”这种式子,那聪明的你肯定可以联想到后缀和前缀,具体是什么了。不错,前缀就是“+12”,
    后缀就是“12+“。
  • 那现在先从第一步开始:如何从中缀表达式变为后缀表达式。 就拿一个简单的例子: (1 + 2) * 3 来做个例子。
    这里写图片描述
    从字符串的头遍历到结尾,第一个遇到了左括号,这个时候,我们先压进栈里,那么栈里的状态如下 那么现在继续迭代
    这里写图片描述
    继续
    这里写图片描述
    现在遇到了1,那么现在后缀表达式就为 : 1
    这里写图片描述
    终于遇到运算符了,那这个时候呢,就应该开始做一些处理。运算符进栈前,得保证进去后,栈顶的运算符的运算优先级是最高的,举个例子,栈里的元素如果是这个样子 ( * , 你要把+号压进去,就得把给pop出来,来保证栈顶的+号是目前运算优先级最高的,所以,当前栈里的状态为:
    这里写图片描述

好,我们继续吧
这里写图片描述
遇到了数字,那么就先放进后缀表达式吧,现在的后缀表达式:1 2
这里写图片描述
现在,遇到右括号了哦,那么,这个时候的规则呢,就是把目前栈里的元素都pop出来,直到遇到左括号
这里写图片描述
所以,这个时候的后缀表达式为:1 2 +(左括号pop出去就丢弃可以了,不用加入后缀表达式)
继续
这里写图片描述
遇到运算符,没什么好说的啦,老规矩

继续
这里写图片描述
这里也没什么特别的,加入后缀表达式吧,此时后缀表达式为:* 1 2 + 3 *
到这里,字符串也迭代完了,好累哟,不过还没大功告成噢,别忘了栈里还有一个残留的运算符,别忘了把它也给pop出去,那么最后的结果:1 2 + 3 就是后缀表达式了啦。


下面就直接上代码吧

 #include <iostream>
 #include <string>
 #include <stack>
 using namespace std;




 class reversePolishNotation {
 public:
    reversePolishNotation(){
    }
    //中缀转后缀表达式 
    string getSuffixExpression(string orginalExpression) {
        int length = orginalExpression.length(); //原中缀表达式的长度 
        stack<char> stk; //存放运算符 
        string res = ""; //记录后缀表达式 
        for (int i = 0; i < length; i++) {
            char c = orginalExpression[i]; 
            if (c == '(') {//左括号 的时候就压栈吧 
                stk.push(c);
            } else if (c == ')') {//右括号时,就一直pop,直到遇到左括号 
                while(!stk.empty() && stk.top() != '(') {
                    res += stk.top();
                    stk.pop();
                }
                if (!stk.empty()) stk.pop();//当然左括号这个时候已经没有用处,也pop 
            } else if (isOpeartor(c)) {//栈顶的运算符的优先级必定是栈内最高的 
                while(!stk.empty() && stk.top() != '('&&priority(stk.top()) >= priority(c)) {
                    res += stk.top();
                    stk.pop();
                }
                stk.push(c);
            } else if (c == ' ') {
                continue;
            } else {
                string num = "";
                while(isNumber(c)) {
                    num += c;
                    c = orginalExpression[++i];
                }
                num += '#';//#这个是我为了辨别数字而设置的一个标记。 
                res += num;
                i--;
            }
        }
        while(!stk.empty()) {//最后还会有运算符在栈中,别忘了pop出来 
            res += stk.top();
            stk.pop();
        }
        return res;//大功告成 
    }

 private:
    //判断运算符的优先级 
    int priority(char c) {
        if ('%' == c || '*' == c || '/' == c) return 1;
        if ('+' == c || '-' == c) return 0;
    }
    //判断是否是运算符 
    bool isOpeartor(char c) {
        if ('/' == c || '*' == c || '+' == c || '-' == c) return true;
        return false;
    }
    //判断是不是数字 
    bool isNumber(char c) {
        if (c >= '0' && c <= '9') return true;
        return false;
    }
    //stoi这个函数貌似在c++11已经有了,只不过是我的编译器没有c++11版本,所以自己手写了一个,其实就几行代码。 
    int stoi(string str) {
        int res = 0;
        for (int i = 0; i < str.length(); i++) {
            res *= 10;
            res += (str[i] - '0');
        }
        return res;
    }
 }; 


 int main() {
    //一个小测试 
    reversePolishNotation s;
    string str = s.getSuffixExpression("122-2+3*2+1/2");
    cout<<str<<endl;//122#2#-3#2#*+1#2#/+
    return 0;
 }

今天就到这吧!共勉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值