一四则运算栈实现,支持小数负数

Posted 寒风晓月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一四则运算栈实现,支持小数负数相关的知识,希望对你有一定的参考价值。

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

思路:

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;
        }
    }
}

 

程序参考了某些博客的文章,但是难以找到原地址,如需注明,请练习本人!

以上是关于一四则运算栈实现,支持小数负数的主要内容,如果未能解决你的问题,请参考以下文章

栈应用之中缀表达式计算C#实现

四则运算2

Java_计算器001,支持加减乘除,括号,小数点,√,^ 运算

Qt之加减乘除四则运算-支持负数

C语言数据结构算法——简单表达式求值(支持计算小数及负数)

PTA-7-20 表达式转换(中缀转后缀,带括号,负数,小数转换)