C++双栈实现带括号的字符串表达式求值。。。。支持double

关于字符串表达式求值的计算,一直以来都很头疼,今天下决心研究了一天,终于完成带括号的字符串算式表达式求值:

例如,输入字符串:1-2*(3/(2-1))#,求值为-5.

特色:

    1、支持double类型的输入

    2、可以支持括号

    3、双栈一次性完成输入和运算

    4、支持混合五则运算

**输入异常,程序退出;

    字符串表达式求值有多重方式,其中最常见的是中缀转后缀,然后用一个栈输入后缀表达式求值,这里我用另一种方式:利用两个栈(操作符栈、操作数栈),来存储读入的字符串表达式,然后根据输入的运算符优先级来判断是否运算,还是进行入栈操作,最终操作数的栈底就是表达式的结果,求吐槽。。。。

    字符串输入以#结束,只支持合法的算术表达式,计算精度为10^(-9)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctype.h>
#include <cassert>
#include <algorithm>
#include <stack>
#include <utility>
#include <cstring>

using namespace std;

void Calculator();///字符串输入加运算判断和去括号
double operater(double left,double right,char ch);///计算函数
///判断输入字符为运算符
bool isOperator(char ch);
///栈内优先级:)、*/%、+-(、#
int isp(char ch);
///栈外优先级:(、*/%、+-、#)
int icp(char ch);
///测试打印两个栈的数据
void printstck(stack<char> stkOpr, stack<double> stkDigit);

int main()
{
    while(1)
        Calculator();
    return 0;
}
void Calculator()
{
    cout<<"please input math expression end with "<<"# ."<<endl;
    cout<<"Example: 1-2*(3/(2-1))# \ninput: ";
    stack<char> stkOpr;
    stack<double> stkDigit;

    string str = "";///存储操作数
    double left,right;
    char ch='#';///存储操作符

    stkOpr.push(ch);///将#好入栈,放在符号栈低,作为运算结束的判断条件

    bool kuohao = false;///表示符判断出栈的是否是括号
    ///输入补位结束符,继续输入
    do
    {
        cin.get(ch) ;///读入字符,开始输入算术表达式

        ///如果是操作数,则进行入栈操作
        if(isdigit(ch) || '.'==ch)
        {
            str.append(1,ch);
            continue;
        }
        else if(isOperator(ch))
        {
            bool flag=true;///标识符判断是否连续输入运算符或者括号
            if(0 == strlen(str.data()))
                flag=false;
            else
            {
                right = atof(str.c_str());///将输入操作数赋给右操作数
                str = "";///清空当前操作数,准备接收新的操作数
            }

            ///比较栈顶与栈外优先级
            char tc = stkOpr.top();///拿到栈顶的操作符
            while(isp(tc)>icp(ch))///栈内优先级大时,循环计算优先级较高的运算
            {
                flag=true;///进行运算相当于输入新的运算数
                if(kuohao)///当上次栈顶为左括号时,将上次入栈的有操作数弹出栈,这里有点绕,得想想
                {
                    stkDigit.pop();
                    kuohao = false;
                }
                printstck(stkOpr,stkDigit);///测试打印两个栈的数据
                if(!stkDigit.empty())
                {
                    ///栈顶操作数出栈赋给左操作数,同时将栈顶元素出栈
                    left = stkDigit.top();
                    stkDigit.pop();
                    ///计算当前运算并将计算结果入栈
                    cout<<"operater order:"<<left<<tc<<right<<endl;
                    right = operater(left,right,tc);
                }
                else
                    break;
                if(!stkOpr.empty())///栈顶操作符出栈
                {
                    stkOpr.pop();///计算过的操作符出栈
                    tc = stkOpr.top();///拿到栈顶的操作符
                }
                else
                    break;
            }
            ///右操作数入栈
            if(flag)
                stkDigit.push(right);

            if(isp(tc)<icp(ch))///栈内优先级小
            {
                ///符号入栈
                stkOpr.push(ch);
            }
            else if(isp(tc)==icp(ch))///栈内优先级小
            {
                if(!stkOpr.empty())///栈顶操作符出栈
                {
                    stkOpr.pop();
                    kuohao = true;
                }
            }

        }///else end
    }while('#'!=ch);///while end
    stkDigit.push(right);///计算结果入栈

    ///表达式输入结束,数字栈栈底为所求表达式的值
    cout<<"result="<<stkDigit.top()<<endl;
}
///计算当前运算
double operater(double left,double right,char ch)
{
    const double DEX = 1/pow(10,9);///定义运算精度
    switch(ch)
    {
    case '+':
        return left+right;
    case '-':
        return left-right;
    case '*':
        return left*right;
    case '/':
        if(DEX>abs(right))
        {
            cout<<"divide by 0! \n please try again!"<<endl;
            exit(1);///异常值,程序退出
        }
        else
            return left/right;
    case '%':
        if(left == (int)left && right == (int)right)
            return (int)left%(int)right;
        else
        {
            cout<<"double type connot operator '%' ! \n please try again!"<<endl;
            exit(1);///异常值,程序退出
        }
    default:
        exit(1);///异常值,程序退出
    }
}

///判断输入字符为运算符
bool isOperator(char ch)
{
    switch(ch)
    {
    case '+':
    case '-':
    case '*':
    case '/':
    case '%':
    case ')':
    case '(':
    case '#':
        return true;
    default:
        return false;
    }
}

///栈内优先级:)、*/%、+-(、#
int isp(char ch)
{
    switch(ch)
    {
    case '(':
        return 1;
    case '+':
    case '-':
        return 3;
    case '*':
    case '/':
    case '%':
        return 5;
    case ')':
        return 6;
    case '#':
        return 0;
    default:
        return -1;
    }
}
///栈外优先级:(、*/%、+-、#)
int icp(char ch)
{
    switch(ch)
    {
    case '(':
        return 6;
    case '+':
    case '-':
        return 2;
    case '*':
    case '/':
    case '%':
        return 4;
    case ')':
        return 1;
    case '#':
        return 0;
    default:
        return -1;
    }
}
///测试打印两个栈的数据
void printstck(stack<char> stkOpr, stack<double> stkDigit)
{
    stack<char> s1;
    stack<double> s2;
    while(!stkOpr.empty())
    {
        s1.push(stkOpr.top());
        stkOpr.pop();
    }
    while(!s1.empty())
    {
        cout<<s1.top()<<" ";
        stkOpr.push(s1.top());
        s1.pop();
    }
    cout<<endl;

    while(!stkDigit.empty())
    {
        s2.push(stkDigit.top());
        stkDigit.pop();
    }

    cout<<" ";
    while(!s2.empty())
    {
        cout<<s2.top()<<" ";
        stkDigit.push(s2.top());
        s2.pop();
    }
    cout<<endl;
}

作者:yanxiaocheng 出处:https://blog.csdn.net/u014474985
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个基于实现的中缀表达式的 C++ 代码示例: ```cpp #include <iostream> #include <stack> #include <string> using namespace std; // 计算两个数的结果 double calculate(double num2, double num1, char oper) { switch (oper) { case '+': return num1 + num2; case '-': return num1 - num2; case '*': return num1 * num2; case '/': return num1 / num2; default: return 0; } } // 判断字符是否为操作符 bool isOperator(char c) { return (c == '+' || c == '-' || c == '*' || c == '/'); } // 中缀表达式函数 double evaluateInfix(string expression) { stack<double> numStack; // 存储数字的 stack<char> operStack; // 存储操作符的 for (int i = 0; i < expression.length(); i++) { char c = expression[i]; // 如果当前字符是空格,直接忽略 if (isspace(c)) { continue; } // 如果当前字符是数字,将其转换为实数并压入数字 if (isdigit(c)) { double num = c - '0'; while (i + 1 < expression.length() && isdigit(expression[i + 1])) { num = num * 10 + (expression[++i] - '0'); } numStack.push(num); } // 如果当前字符是操作符,将其压入操作符 else if (isOperator(c)) { while (!operStack.empty() && operStack.top() != '(' && ((c != '*' && c != '/') || (operStack.top() != '+' && operStack.top() != '-'))) { double num2 = numStack.top(); numStack.pop(); double num1 = numStack.top(); numStack.pop(); numStack.push(calculate(num2, num1, operStack.top())); operStack.pop(); } operStack.push(c); } // 如果当前字符是左括号,将其压入操作符 else if (c == '(') { operStack.push(c); } // 如果当前字符是右括号,不断弹出操作符顶的操作符并计算,直到遇到左括号为止 else if (c == ')') { while (!operStack.empty() && operStack.top() != '(') { double num2 = numStack.top(); numStack.pop(); double num1 = numStack.top(); numStack.pop(); numStack.push(calculate(num2, num1, operStack.top())); operStack.pop(); } operStack.pop(); // 弹出左括号 } } // 将剩余的操作符计算完 while (!operStack.empty()) { double num2 = numStack.top(); numStack.pop(); double num1 = numStack.top(); numStack.pop(); numStack.push(calculate(num2, num1, operStack.top())); operStack.pop(); } return numStack.top(); // 返回最终结果 } int main() { string expression = "3 + 4 * (2 - 1)"; double result = evaluateInfix(expression); cout << expression << " = " << result << endl; return 0; } ``` 以上代码实现了一个简单的中缀表达式函数,其中使用了两个分别存储数字和操作符。在遍历表达式字符串时,对于不同类型的字符会进行不同的处理: - 如果是数字,将其转换为实数并压入数字。 - 如果是操作符,从操作符中弹出相应的操作数,并进行计算,将结果压入数字。 - 如果是左括号,将其压入操作符。 - 如果是右括号,不断弹出操作符顶的操作符并计算,直到遇到左括号为止。 最终,在遍历完整个字符串后,将剩余的操作符依次计算即可得到最终结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值