码迷,mamicode.com
首页 > 编程语言 > 详细

【算法学习笔记】86.栈 中缀表达式 SJTU OJ 1033 表达式计算

时间:2015-07-29 00:46:58      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:

...被输入给坑了 应该先把所有的空格删掉再玩  还有就是测试点里好像根本就没有关于后结合的事情...不过后结合也很简单 控制一下优先级的判断即可.

中缀表达式的处理核心就是两个堆栈的维护

一个是 操作符

一个是 操作数

只有当 当前正在处理的操作符的优先级大于(不考虑后结合时) 栈顶操作符的时候, 才进行计算.(或者出现右括号时 一直计算到左括号出现)

代码比较长 用了struct来存储token 比较清晰.

#include <iostream>
#include <stack>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <sstream>
#include <cmath>
using namespace std;
struct Token
{
    enum token_type
    {
        NUMBER = 1, OP=2
    }type;
    long long number;
    string op;
    int priority;
};

vector<Token> tokens;//语法单元集合
stack<long long> number_stack;//操作数栈
stack<Token> op_stack; //运算符栈

bool init(){
    string input;//todo expression
    
    getline(cin,input);
    string xpr = "";
    for (int i = 0; i < input.length(); ++i) {
        if(input[i]!= )
            xpr+=input[i];
    }
    Token tmp;
    for (int i = 0; i < xpr.length(); ++i)
    {
        switch(xpr[i]){
            case  :
                continue;
                break;
            case +:
                tmp.type = Token::OP;
                tmp.op = "+";
                tmp.priority = 1;
                break;
            case -: //两种情况
                if(i>=1 and (xpr[i-1]==) or isdigit(xpr[i-1])))//作为减号使用
                {
                    tmp.type = Token::OP;
                    tmp.op = "-";
                    tmp.priority = 1;
                }else{ //作为负号使用(取反运算)
                    tmp.type = Token::OP;
                    tmp.op = "$";//特殊标记
                    tmp.priority = 10;//优先级最高 单元运算符 取反
                }
                break;
            case *:
                tmp.type = Token::OP;
                tmp.op = "*";
                tmp.priority = 2;
                break;
            case /:
                tmp.type = Token::OP;
                tmp.op = "/";
                tmp.priority = 2;
                break;
            case ^://
                tmp.type = Token::OP;
                tmp.op = "^";
                tmp.priority = 3;
                //if(tokens.size()>=2 and tokens[tokens.size()-2].op=="^")
                //   tmp.priority = tokens.back().priority + 1;
                break;
            case (:
                tmp.type = Token::OP;
                tmp.op = "(";
                tmp.priority = 0;
                break;
            case ):
                tmp.type = Token::OP;
                tmp.op = ")";
                tmp.priority = 4;
                break;
            default: //是数字了
                string num = "";
                while( i < xpr.length() and isdigit(xpr[i]))
                    num += xpr[i++];
                //由于循环外侧还有一个i++ 所以这里要-1
                --i;
                stringstream ss;
                ss<<num;
                ss>>tmp.number;
                tmp.type = Token::NUMBER;
                tmp.op = "";
                break;
        }
        tokens.push_back(tmp);
    }
    return true;
}


//进行计算
bool calc(Token op){
    long long a , b;
    if((op.op=="$" and number_stack.empty()) or (op.op!="$" and number_stack.size()<2))
        return false;
    if(op.op == "$"){
        a = number_stack.top();number_stack.pop();
        number_stack.push(-1*a);
    }else if(op.op=="+"){
        a = number_stack.top();number_stack.pop();
        b = number_stack.top();number_stack.pop();
        number_stack.push(b+a);
    }else if(op.op=="-"){
        a = number_stack.top();number_stack.pop();
        b = number_stack.top();number_stack.pop();
        number_stack.push(b-a);
    }else if(op.op=="*"){
        a = number_stack.top();number_stack.pop();
        b = number_stack.top();number_stack.pop();
        number_stack.push(b*a);
    }else if(op.op=="/"){
        a = number_stack.top();number_stack.pop();
        b = number_stack.top();number_stack.pop();
        if(a==0) //除零错
            return false;
        number_stack.push(b/a);
    }else if(op.op=="^"){
        //右结合稍后处理
        a = number_stack.top();number_stack.pop();
        b = number_stack.top();number_stack.pop();
        number_stack.push((long long)pow(b, a));
    }
    return true;
}

bool build(){
    for (int i = 0; i < tokens.size() ; ++i) {
        if(tokens[i].type == Token::OP){ //是操作符
            if(tokens[i].op=="("){
                op_stack.push(tokens[i]);
                
            }else if(tokens[i].op==")"){// 一直pop 直到找到了左括号//如果没有一直没有遇到左括号则报错
                
                while( !op_stack.empty() and op_stack.top().op != "("){
                    if(!calc(op_stack.top()))   return false;
                    op_stack.pop();
                }
                //处理一下左括号
                if(op_stack.empty())
                    return false;
                if(op_stack.top().op == "(")
                    op_stack.pop();
            }else{ // + - * / $
                
                if(op_stack.empty())
                    op_stack.push(tokens[i]);
                else{
                    int top_pr = op_stack.top().priority;
                    int cur_pr = tokens[i].priority;
                    //如果当前的运算符的优先级 比 栈顶优先级高的话
                    if( cur_pr > top_pr or (tokens[i].op =="^" and op_stack.top().op=="^")){
                        op_stack.push(tokens[i]);
                    }else{
                        while(cur_pr <= top_pr){ //如果当前运算符的优先级比栈顶的优先级低或者等于的时候 就不断计算
                            if(!calc(op_stack.top()))   return false;
                            op_stack.pop();
                            if(op_stack.empty())
                                break;
                            top_pr = op_stack.top().priority;
                        }
                        //现在可以把正在处理的运算符入栈了
                        op_stack.push(tokens[i]);
                    }
                }
                
            }
        }else if(tokens[i].type==Token::NUMBER){//是操作数
            number_stack.push(tokens[i].number);
        }
    }
    //进行运算
    while (!op_stack.empty()){
        if(op_stack.top().op=="(")
            return false;
        if(!calc(op_stack.top()))
            return false;
        op_stack.pop();
    }
    return (number_stack.size()==1);
}


void print(){
    for (int i = 0; i<tokens.size(); ++i) {
        if(tokens[i].type==Token::NUMBER){
            cout<<"number:"<<tokens[i].number<<endl;
        }else{
            cout<<"op:"<<tokens[i].op<<"   pri:"<<tokens[i].priority<<endl;
        }
        //cout<<tokens[i].number <<" " << tokens[i].type << " " << tokens[i].priority<< " " << tokens[i].op <<endl;
    }
}
int main(int argc, char const *argv[])
{
    
    if(init()){
        if(build()){
            cout<<number_stack.top()<<endl;
        }
        else{
            cout<<"Error"<<endl;
        }
    }else
        cout<<"Error"<<endl;
    
    return 0;
}

 

【算法学习笔记】86.栈 中缀表达式 SJTU OJ 1033 表达式计算

标签:

原文地址:http://www.cnblogs.com/yuchenlin/p/sjtu_oj_1033.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!