zoukankan      html  css  js  c++  java
  • 四则运算栈实现,支持小数、负数

    四则运算栈实现,支持小数、负数,经过测试,暂时没发现错误!

    思路:

    1、去掉字符串中的空格,将字符串按照运算符和数字保存到vector<string>中;

    2、判断字符串是否符合四则运算的表达式;

    3、栈实现:数字栈、运算符栈,从左到右扫描中缀表达式;

    数字:直接入栈;运算符:

    (1)”(“:直接入栈;

    (2)”)“:弹出()之间的运算符,进行运算;

    (3)”+-*/“:如果当前运算符优先级<栈顶运算符优先级,则数字栈弹出两个数和栈顶运算符进行运算,并将结果存入数字运算符,再将当前运算符入栈;否则直接入栈。

    扫描结束后,如果运算符栈还有元素,则出栈运算。

    负数:支持5+-3这样的写法,扫描到”-“,判断”-“是减号还是负号;    

       ”-“前面一个字符是数字或者”)“,则认为是减号;否则是负号;

       如果当前字符是负号,将标志isNeg=true,则下一个数字存入vector<string>中时,加上负号。

    小数:支持.1这样的写法,小数点”.“与数字字符的处理方式相同。

    #include <iostream>
    #include <string>
    #include <stack>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    //打印输出容器
    template <typename T> 
    void print(const T& v)
    {
        for(size_t i = 0; i < v.size(); ++i)
        {
            cout << v[i] << " ";
        }
        cout << endl;
    }
    //运算符优先级
    int getPriority(const string& op)
    {
        int priority;
        if (op == "#")
            priority = 3;
        else if (op == "*" || op == "/")
            priority = 2;
        else if (op == "+" || op == "-")
            priority = 1;
        else 
            priority = -1;
        return priority;
    }
    //将字符串表达式分开
    vector<string> preParse(const char* str)
    {
        vector<string> tokens;
        int len = strlen(str);
        char *p = (char*)malloc((len+1)*sizeof(char));
        int i = 0, j = 0;
        //去掉空格
        while(i < len)
        {
            if(str[i] == ' ')
            {
                ++i;
                continue;
            }
            p[j++] = str[i++];
        }
        p[j] = '\0';
        j = 0;
        len = strlen(p);
        bool isNeg = false;
        while (j < len)
        {
            char temp[2];
            string token;
            switch(p[j])
            {
                case '+':
                case '*':
                case '/':
                case '(':
                case ')':
                    temp[0] = p[j];
                    temp[1] = '\0';
                    token = temp;
                    tokens.push_back(token);
                    break;
                case '-':
                    if(j == 0)
                    {
                        //tokens.push_back("#");
                        isNeg = true;
                    }
                    else if (p[j-1] == ')' || isdigit(p[j-1]))
                    {
                        tokens.push_back("-");
                    }
                    else
                    {
                        //tokens.push_back("#");
                        isNeg = true;
                    }
                    break;
                default:
                    i = j;
                    while (  (   isdigit(p[i]) || p[i] =='.'   ) && i < len)
                    {
                        i++;
                    }
                    char *num = (char*)malloc(i-j+2);
                    strncpy(num, p+j, i-j+1);
                    num[i-j] = '\0';
                    if (isNeg)
                    {
                        char *temp = (char*)malloc(i-j+3);
                        temp[0] = '-';
                        strcpy(temp+1, num);
                        tokens.push_back(temp);
                        isNeg = false;
                    }
                    else
                    {
                        tokens.push_back(num);
                    }
                    
                    j = i - 1;
                    free(num);
                    break;
            }
            j++;
        }
        free(p);
        //print(tokens);
        return tokens;
    }
    
    //两个数运算
    void calculate(stack<double> & opdStack, string opt)
    {
        if(opt == "#")
        {
            double opd = opdStack.top();
            double result = 0 - opd;
            opdStack.pop();
            opdStack.push(result);
        }
        else 
        {
            double rOpd = opdStack.top();
            opdStack.pop();
            double lOpd = opdStack.top();
            opdStack.pop();
            double result;
            if(opt == "+")        result = lOpd + rOpd;
            else if(opt == "-")   result = lOpd - rOpd;
            else if(opt == "*")   result = lOpd * rOpd;
            else if(opt == "/")   result = lOpd / rOpd;
            opdStack.push(result);
        }
    }
    
    
    //计算
    double process(string &str)
    {
        char *s = (char *)malloc(str.size());
        strcpy(s, str.c_str());
        vector<string> tokens = preParse(s);
        int i = 0;
        int size = tokens.size();
    
        stack<double> opdStack;    //num
        stack<string> optStack;    //op
        for(i = 0; i < size; ++i)
        {
            string token = tokens[i];
            if(token=="#"||token=="+"||token=="-"||token=="*"||token=="/")
            {
                if(optStack.size() == 0)
                {
                    optStack.push(token);
                }
                else
                {
                    int tokenPriority = getPriority(token);
                    string topOpt = optStack.top();
                    int topOptPritority = getPriority(topOpt);
                    if(tokenPriority > topOptPritority)
                    {
                        optStack.push(token);
                    }
                    else
                    {
                        while(tokenPriority <= topOptPritority)
                        {
                            optStack.pop();
                            calculate(opdStack, topOpt);
                            if(optStack.size()>0)
                            {
                                topOpt = optStack.top();
                                topOptPritority = getPriority(topOpt);
                            }
                            else
                            {
                                break;
                            }
                        }
                        optStack.push(token);
                    }
                }
            }
            else if(token == "(")
            {
                optStack.push(token);
            }
            else if(token == ")")
            {
                while(optStack.top() != "(")
                {
                    string topOpt = optStack.top();
                    calculate(opdStack,topOpt);
                    optStack.pop();
                }
                optStack.pop();
            }
            else
            {
                opdStack.push(stod(token));
            }
        }
        while(optStack.size() != 0)
        {
            string topOpt = optStack.top();
            calculate(opdStack,topOpt);
            optStack.pop();
        }
        return opdStack.top();
    }
    
    //判读是否错误
    //1 有除数字、+-*/()外的字符
    //2 首字符是+*/
    //3 括号不匹配
    //4 除数为0
    bool isRight(const string &str)
    {
        string c1 = "0123456789+-*/().";
        string c2 = "0123456789";
    
        if (str.find_first_of(c2) == string::npos)
        {
            cout << "表达式中没有可计算的数字!" << endl;
            return false;
        }
        if (str.find_first_not_of(c1) != string::npos)
        {
            cout << "表达式中有除数字、+-*/()外的非法字符!" << endl;
            return false;
        }
        if (str[0] == '+' || str[0] == '/' || str[0] == '*')
        {
            cout << "表达式中首字符错误!" << endl;
            return false;
        }
        if (  count(str.cbegin(),str.cend(),'(')   !=   count(str.cbegin(),str.cend(),')') )
        {
            cout << "表达式中括号不匹配!" << endl;
            return false;
        }
    
        char *s = (char *)malloc(str.size());
        strcpy(s, str.c_str());
        vector<string> tokens = preParse(s);
        for (auto it = tokens.cbegin(); it != tokens.cend(); ++it)
        {
            if (*it == "/")
            {
                ++it;
                if(*it == "0")
                {
                    cout << "除数不能为0!" << endl;
                    return false;
                }
            }
            if(*it == "/" || *it == "*"|| *it == "+" || *it == "-" )
            {
                ++it;
                if(*it == "/" || *it == "*"|| *it == "+" || *it == "-" )
                {
                    cout << "运算符相邻无法计算!" << endl;
                    return false;
                }
            }
        }
        return true;
    
    }
    int main()
    {
        
        while (1)
        {
            string str;
            cout << "input:";
            cin >> str;
            
            if( isRight(str) )
            {
                cout << "result:"<<process(str) << endl;
            }
        }
    }

    参考:http://www.cnblogs.com/dolphin0520/p/3708602.html

  • 相关阅读:
    BZOJ-2431: [HAOI2009]逆序对数列 (傻逼递推)
    BZOJ3695 滑行
    BZOJ3689 异或之
    BZOJ3696 化合物
    BZOJ1393 [Ceoi2008]knights
    BZOJ2280 [Poi2011]Plot
    BZOJ1570 [JSOI2008]Blue Mary的旅行
    BZOJ2751 [HAOI2012]容易题(easy)
    BZOJ2818 Gcd
    BZOJ2426 [HAOI2010]工厂选址
  • 原文地址:https://www.cnblogs.com/pukaifei/p/5346463.html
Copyright © 2011-2022 走看看