解析表达式 四则运算

来源:互联网 发布:淘宝宝贝产品参数 编辑:程序博客网 时间:2024/06/18 08:14

解析表达式 四则运算

本人刚上大二,大一时候写过解析表达式,当时没有听说过什么逆波兰解析,也没有听说过后缀表达式,数据结构也还没学。所以只能根据正常人的思维进行暴力求解。
第一种方法(中缀表达式):
基本思想是:
1.分开存入,逐步计算。
(数字提取存到结构体数组中的成员里)
2.遇到符号优先级,进行比较。
(一元运算符(函数运算符)要优先处理!)
3.括号处理(递归算法)。
4.最终计算(依次序出栈,按元数计算即可

话不多说**,下面附上中缀表达式(后来才知道)的代码:

//Expression.h#pragma onceclass Expression{public:    int isNum(char c);    int canInStack(char old, char in);    double twoMenCalc(char f, double old, double top);    int strPro(char * str);    double calculate(Expression* content, int signnum);    double calculateAll();private:    char m_cont[20];            //存放表达式的操作符.    double m_num;               //存放数字,为方便识别,在对应的cont[]中存放'n'.};//Expression.cpp#include <math.h>#include <conio.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include<iostream>#include "Expression.h"using namespace std;Expression content[100];                //定义结构体数组.用来存放扫描分割的表达式.int signnum = 0;                        //记录表达式长度.(重要的全局变量)//找出数字.int Expression::isNum(char c){    if (c >= '0' && c <= '9')    {        return 1;    }    else    {        return 0;    }}//判断优先级.int Expression::canInStack(char old, char in){    if ((old == '*' || old == '/') && (in == '^'))    {        return 1;    }    if ((old == '+' || old == '-') && (in == '*' || in == '/' || in == '^'))    {        return 1;    }    return 0;}//二元运算符的计算.double Expression::twoMenCalc(char f, double old, double top){    double out = 0;    switch (f)    {    case '+':        out = old + top;        break;    case '-':        out = old - top;        break;    case '*':        out = old * top;        break;    case '/':        out = old / top;        break;    case '^':        out = pow(old, top);;        break;    case '.':        int decPos = 0;        int sign = 0;        cout << ecvt(top, 0, &decPos, &sign);        double xiaoshu = double(top / pow(10, decPos));        out = old + xiaoshu;    }    return out;}//扫描分割表达式,存入相应的数组中.int Expression::strPro(char * str){    signnum = 0;    //初步判断,如果末尾不是x或者)或者末尾是操作符就报错.    if ((str[strlen(str) - 1] != ')' && str[strlen(str) - 1] != 'x' && !isNum(str[strlen(str) - 1])) || str[0] == '+'  || str[0] == '*' || str[0] == '/' || str[0] == '^') {        return -1;    }    int i = 0;      //表达式字符串下标    int flag = 0;   //标志位    //解决负数.    char str1[100] = {NULL};    if (str[0] == '-') {        str1[0] = '0';        strcat(str1, str);    }    else {        strcat(str1, str);    }    while (i < strlen(str1))//i小于这个表达式的长度的时候.    {        if (str1[i] == '+')        {            content[signnum].m_cont[0] = str1[i];            content[signnum].m_cont[1] = '\0';            signnum++;            i += 1;        }        else if (str1[i] == '-')        {               content[signnum].m_cont[0] = str1[i];            content[signnum].m_cont[1] = '\0';            signnum++;            i += 1;        }        else if (str1[i] == '*')        {                   content[signnum].m_cont[0] = str1[i];            content[signnum].m_cont[1] = '\0';            signnum++;            i += 1;        }        else if (str1[i] == '/')        {                       content[signnum].m_cont[0] = str1[i];            content[signnum].m_cont[1] = '\0';            signnum++;            i += 1;        }        else if (str1[i] == '^')        {                               content[signnum].m_cont[0] = str1[i];            content[signnum].m_cont[1] = '\0';            signnum++;            i += 1;        }        else if (str1[i] == '(')        {                           content[signnum].m_cont[0] = str1[i];            content[signnum].m_cont[1] = '\0';            signnum++;            i += 1;        }        else if (str1[i] == ')')        {                           content[signnum].m_cont[0] = str1[i];            content[signnum].m_cont[1] = '\0';            signnum++;            i += 1;        }        else if (isNum(str1[i]))        {                       int number = 0;            int j;            for (j = i; j < strlen(str1); j++)            {                               //将数字找出                if (isNum(str1[j]))                {                    number = number * 10 + str1[j] - '0';//输入的是字符串,转化成数字                }                                       //迭代计算出数字.                else {                    break;                }            }            content[signnum].m_num = number;            //将number值赋给结构体变量.            content[signnum].m_cont[0] = 'n';            content[signnum].m_cont[1] = '\0';            signnum++;            i += (j - i);        }        else if (str1[i] == '.') {            content[signnum].m_cont[0] = str1[i];            content[signnum].m_cont[1] = '\0';            signnum++;            i += 1;            int number = 0;            int j;            for (j = i + 1; j < strlen(str1); j++)            {                               //将数字找出                if (isNum(str1[j]))                {                    number = number * 10 + str1[j] - '0';//输入的是字符串,转化成数字                }                                       //迭代计算出数字.                else {                    break;                }            }            content[signnum].m_num = number;            //将number值赋给结构体变量.            content[signnum].m_cont[0] = 'n';            content[signnum].m_cont[1] = '\0';            //twoMenCalc('.', content[signnum - 1].m_num, number);            signnum++;            i += (j - i);        }        else        {                           //如果输入出错,保险起见.            flag = 1;            break;        }    }    if (flag>0)    {                               //出错        return -1;    }    else    {        return 0;    }}//计算子式.double Expression::calculate(Expression * content, int signnum){    double output = 0;      //输出值    double opns[100];       //操作数    int opnsi = 0;          //计数操作数    char opss[100];         //操作符、+-    int opssi = 0;          //计数操作符、+-    memset(opss, '\0', 100);    memset(opns, NULL, 100);    //不考虑输入有问题的情形,第一个肯定是二元操作数.    opns[opnsi++] = content[0].m_num;    //i=1;    for (int i = 1; i < signnum; i++)    {        if (content[i].m_cont[0] == 'n')        {            opns[opnsi++] = content[i].m_num;        }        if (strcmp(content[i].m_cont, "+") == 0){            if (opssi == 0)            {                opss[opssi++] = '+';            }            else            {                if (opssi != 0 && canInStack(opss[opssi - 1], '+'))     //opss[opssi - 1]注意位置                {                                                       //可以入栈                    opss[opssi++] = '+';                }                else                {                                               //出栈                    double temp;                    if (opnsi > 1)                    {                        //弹出两个操作数,进行二元计算之后放入栈顶.                        opns[opnsi - 2] = twoMenCalc(opss[opssi - 1], opns[opnsi - 2], opns[opnsi - 1]);                        opns[opnsi - 1] = NULL;                        opnsi--;                        opss[opssi - 1] = '+';                    }                }            }    }        if (strcmp(content[i].m_cont, "-") == 0)        {            if (opssi == 0)            {                opss[opssi++] = '-';            }            else {                if (opssi != 0 && canInStack(opss[opssi - 1], '-'))                {       //可以入栈                    opss[opssi++] = '-';                }                else {      //出栈                    double temp;                    //运算                    if (opnsi > 1)                    {                        opns[opnsi - 2] = twoMenCalc(opss[opssi - 1], opns[opnsi - 2], opns[opnsi - 1]);                        opns[opnsi - 1] = NULL;                        opnsi--;                        opss[opssi - 1] = '-';                    }                }            }        }        if (strcmp(content[i].m_cont, "*") == 0)        {            if (opssi == 0)            {                opss[opssi++] = '*';            }            else {                if (opssi != 0 && canInStack(opss[opssi - 1], '*'))                {       //可以入栈                    opss[opssi++] = '*';                }                else {      //出栈                    double temp;                    //运算                    if (opnsi > 1)                    {                        opns[opnsi - 2] = twoMenCalc(opss[opssi - 1], opns[opnsi - 2], opns[opnsi - 1]);                        opns[opnsi - 1] = NULL;                        opnsi--;                        opss[opssi - 1] = '*';                    }                }            }        }        if (strcmp(content[i].m_cont, "/") == 0)        {            if (opssi == 0)            {                opss[opssi++] = '/';            }            else            {                if (opssi != 0 && canInStack(opss[opssi - 1], '/'))                {       //可以入栈                    opss[opssi++] = '/';                }                else                {       //出栈                    double temp;                    //运算                    if (opnsi > 1)                    {                        opns[opnsi - 2] = twoMenCalc(opss[opssi - 1], opns[opnsi - 2], opns[opnsi - 1]);                        opns[opnsi - 1] = NULL;                        opnsi--;                        opss[opssi - 1] = '/';                    }                }            }        }        if (strcmp(content[i].m_cont, "^") == 0)        {            if (opssi == 0)            {                opss[opssi++] = '^';            }            else            {                if (opssi != 0 && canInStack(opss[opssi - 1], '^')) {       //可以入栈                    opss[opssi++] = '^';                }                else                {   //出栈                    double temp;                    //运算                    if (opnsi > 1)                    {                        opns[opnsi - 2] = twoMenCalc(opss[opssi - 1], opns[opnsi - 2], opns[opnsi - 1]);                        opns[opnsi - 1] = NULL;                        opnsi--;                        opss[opssi - 1] = '^';                    }                }            }        }    }    //最后的计算.    double temp = 0;    //+、-、*、/、^    if (opnsi >= 2)//如果操作数大于等于2,同样也可以做如果二元运算符符号数大于等于1    {        for (int mm = opnsi; mm > 1; mm--)        {            if (opssi > 0)            {                temp = twoMenCalc(opss[opssi - 1], opns[mm - 2], opns[mm - 1]);                opns[mm - 1] = NULL;                opns[mm - 2] = temp;                opss[opssi - 1] = '\0';                opssi--;                opnsi--;            }        }    }    output = opns[opnsi - 1];    //输出返回值    return output;}//括号处理double Expression::calculateAll(){    double out = 0;    Expression contentT[100];           //临时结构体变量.    int signnumT = 0;                   //括号内表达式长度.    Expression contentOut[100];         //最终版结构体变量.    int signnumOut = 0;    for (int i = 0; i < signnum; i++)    {        if (content[i].m_cont[0] != ')')        {            //strcpy是遇到'\0'就停止.            strcpy(contentOut[signnumOut].m_cont, content[i].m_cont);            contentOut[signnumOut].m_num = content[i].m_num;            signnumOut++;        }        else            //找到(的位置        {            int t = 0;            double temp = 0;            for (int j = signnumOut - 1; j >= 0; j--)            {                if (contentOut[j].m_cont[0] == '(')                {                    t = j;                    break;                }            }            //定义临时结构体变量存放括号内的表达式.            signnumT = 0;            //将结构体清零操作,便于每次输入不同的表达式进行操作.            memset(contentT, 0, sizeof(Expression) * 100);            for (int j = t + 1; j < signnumOut; j++)            {                strcpy(contentT[signnumT].m_cont, contentOut[j].m_cont);                contentT[signnumT].m_num = contentOut[j].m_num;                signnumT++;            }            temp = calculate(contentT, signnumT);//递归            int t2 = signnumOut;        //位置就是signnumOut                for (int j = t; j < t2; j++)            {                strcpy_s(contentOut[j].m_cont, "\0");                contentOut[j].m_num = NULL;                signnumOut--;                         //对括号内部的进行清零处理            }            //将之前的递归得到的结果存进去.            strcpy(contentOut[signnumOut].m_cont, "n");            contentOut[signnumOut].m_num = temp;            signnumOut++;        }    }    out = calculate(contentOut, signnumOut);//最后用一次递归!    return out;}//main.cpp#include"Expression.h"#include<iostream>#include<string>#include <conio.h>using namespace std;void main() {    double y = 0;    char charget;    do {        printf("1.解析表达式\n");        printf("2.退出\n");        do {            printf("请输入你要使用的功能编号:");            charget = getchar();        } while ((charget != '1') && (charget != '2'));        switch (charget)        {        case '1':            Expression A;            //char str[100] = "3*(4+7)-6*2";//"3x+sin(3+x)-sin3x";//"x+1+22*3-4/2+tansincoslnsqrtx-4^2";            char str[100];            cout << "请输入你要解析的表达式:" << endl;            cin >> str;            if (A.strPro(str) == -1) {                cout << "输入有误请检查" << endl;            }            cout << "计算结果为:" << endl;            y = A.calculateAll();            //用cout输出,因为cout是重载了的,所以会自动判断是什么类型。            cout << y << endl;            cout << endl;            printf("按任意键即可返回主菜单\n");            cout << endl;            getch();            break;        case '2':            exit(0);        }    } while (charget != '2');    system("pause");}

第二种方法(后缀表达式):
大一下学习了后缀表达式和C++数据结构中的栈之后发现用后缀表达式的思想可以很好地解决此类问题,尤其是对括号问题的解决。

#include <stack>#include <cstring>#include <cstdio>#include <stdio.h>#include<cstring>#include <cstdlib>#include <cmath>#include<iostream>using namespace std;char Precede(char a, char b){    int i, j;    char table[8][8] = {        { ' ','+','-','*','/','(',')','=' },        { '+','>','>','<','<','<','>','>' },        { '-','>','>','<','<','<','>','>' },        { '*','>','>','>','>','<','>','>' },        { '/','>','>','>','>','<','>','>' },        { '(','<','<','<','<','<','=',' ' },        { ')','>','>','>','>',' ','>','>' },        { '=','<','<','<','<','<',' ','=' }    };    for (i = 0; i<8; i++)        if (table[0][i] == a)            break;    for (j = 0; j<8; j++)        if (table[j][0] == b) // the first column, different rows            break;    return table[j][i]; // locate the row, and column}bool Calcu_temp(double a, char theta, double b, double &r){    if (theta == '+')        r = a + b;    else        if (theta == '-')            r = a - b;    else        if (theta == '*')            r = a * b;        else        {            if (abs(b - 0.0)<1e-8)                return false;            else                r = a / b;        }    return true;}bool IsOper(char ch){    char ptr[7] = { '+','-','*','/','(',')','=' };    int i;    for (i = 0; i<7; i++)    {        if (ch == ptr[i])            return true;    }    return false;}bool Calculate(char s[], double &result) //计算表达式的结果{    char theta;    int i = 0, j, point = 0;    double a, b, r, num = 0;    //在此开辟两个栈.    stack<double> num_stack;    stack<char> oper_stack; //运算符栈    oper_stack.push('=');    while (s[i] != '=' || oper_stack.top() != '=')//对表达式a进行计算    {        if ((s[i] >= '0' && s[i] <= '9') || s[i] == '.') //字符是数字或者小数点        {            num = 0;//初始化数字为0            point = 0;//point用来标记是否出现小数点以及当前处于小数点后第x位,point==10^x            if (s[i] == '.')                point = 10;            else                num = s[i] - '0';            j = i + 1;            while (!IsOper(s[j])) //继续往后查找并记录该数字,直到该数字结束遇到运算符为止            {                if (s[j] == '.')                {                    point = 10;                    j++;                    continue;                }                if (!point)//整数部分                    num = num * 10 + (s[j] - '0');                else//小数部分                {                    num = num + 1.0 * (s[j] - '0') / point;//小数部分                    point *= 10;//小数位数后移一位                }                j++;            }            i = j;            num_stack.push(num);//将该数字压入栈中        }        else if (IsOper(s[i]))//字符是运算符        {            switch (Precede(s[i], oper_stack.top())) //该运算符和栈顶运算符进行优先级比较并做相关处理            {            case '<':                oper_stack.push(s[i++]);                break;            case '=':                oper_stack.pop();                i++;                break;            case '>':                theta = oper_stack.top();//从栈中弹出一个运算符进行计算                oper_stack.pop();                b = num_stack.top();//弹出两个数字,注意顺序,先弹出的数是第二个操作数                num_stack.pop();                a = num_stack.top();                num_stack.pop();                if (Calcu_temp(a, theta, b, r))//计算并判断是否有除数等于0的情况                    num_stack.push(r);//若正常,则将结果压入栈中                else                    return false;//出现除数为0的情况,返回错误信息                break;            }        }    }    result = num_stack.top();//最后数字栈中的数即为表达式的最终结果    return true;}bool Check(char s[])//检查表达式括号是否匹配{    int flag = 0, i;    for (i = 0; s[i] != 0; i++) {        if (s[i] == '(')            flag++;        if (s[i] == ')')            flag--;    }    if (flag != 0)        return false;    else        return true;}int main(){    //freopen("in.txt", "r", stdin);    int i, j;    char s1[210], s2[210];    double result;    cout << "请输入表达式:";    cin >> s1;//输入表达式    if (strlen(s1) == 1 && s1[0] == '0') // 输入为 ‘0’或只有一个字符时,重新输入        return 0;        for (i = 0, j = 0; s1[i] != 0; i++)//将表达式转换为规格化的表达式,并在末尾加上“=”,保存在s2中        {            if (s1[i] == ' ')                continue;            s2[j++] = s1[i];        }        s2[j++] = '=';        s2[j] = '\0';        if (Check(s2)) //检查括号是否匹配        {            if (Calculate(s2, result))//计算并检查表达式中是否出现除数为0的情况                printf("%lf\n", result);            else                printf("零不能做除数!\n");        }        else            printf("括号匹配出错\n");    //system("pause");    //return 0;        main();}

第三种方法(递归):
首先我们来看表达式的定义,表达式实质上就是一个递归的定义,为什么这么说呢?我们来看下面一幅图就知道了:
表达式定义的流程图

表达式是由若干个项加减组成的,项是由若干个因子乘除组成的,而因子一部分是整数(或者小数)和表达式组成的,在这里便构成了一个递归的定义!

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<cstdlib>using namespace std;double expression_value(); double term_value();double factor_value();double expression_value() {    double result = term_value();    bool flag = true;    while (flag) {        char op = cin.peek();        if (op == '+' || op == '-') {            cin.get();            double value = term_value();//取出下一项.            if (op == '+')  result += value;            else            result -= value;            }        else flag = false;    }    return result;}double term_value() {    double result = factor_value();    bool flag = true;    while (flag) {        char op = cin.peek();        if (op == '*' || op == '/') {            cin.get();            double value = factor_value();//取出下一项.            if (op == '*')  result *= value;            else            result /= value;        }        else flag = false;    }    return result;}double factor_value() {    double result = 0,xiaoshu = 0, i = 0.1;    char op = cin.peek();    if (op == '(') {        cin.get();        result = expression_value();//对括号里的表达式处理,递归!        cin.get();    }    else {        while (isdigit(op)) {            result = 10 * result + op - '0';            cin.get();            op = cin.peek();        }        //处理小数.        if (op == '.') {            cin.get();            op = cin.peek();}        while (isdigit(op)) {            xiaoshu +=(op - '0')*i;            i *= 0.1;            cin.get();            op = cin.peek();}    }    return result+xiaoshu;}void main() {    //string s;    //cin >> s;    cout << "请输入表达式:" << endl;    cout << expression_value() << endl;    system("pause");}

第三种方法相当精炼,没有使用数据结构也没有使用C++的模板库。但是很有效率的解决了解析表达式的问题。

原创粉丝点击