C语言 数据结构题 数学表达式求值

C语言 数据结构题目——数学表达式求值

输入:通过 ”命令行参数“输入一个数学表达式。
输出:(1)表达式正确的情况下输出结果;(2)命令行参数不正确输出字符串ERROR_01;
(3)表达式存在格式错误输出字符串ERROR_02;(4)表达式在计算过程中出现逻辑错误输出字符串ERROR_03。
简明示例:
输入:(2+3)(3-1)^3 输出:40; 输入:((2+3)(3-1)^3输出:ERROR_02

注:1)数学表达式需支持小数、加减乘除、小括号、中括号、幂运算。为简化逻辑,不需要考虑负数情况。
2)不正确的表达式可能包括:字母、非运算符号、括号不匹配,运算符的排列不符合表达式形式等多种情况。
3)输出结果中有几位小数就输出几位小数。
4)表达式通过命令行参数读取 。

序号 表达式 结果 设计意图
1 1+2+3+4 10 加法测试
2 10-8-7-6 -13 减法测试
3 1234 24 乘法测试
4 8/2/2/2 1 除法测试
5 3^2+4^2
2 41 幂运算测试
6 (3+2)2/(4-1+2) 2 括号及优先级测试
7 1+[2-(3
4)] -9 括号及优先级测试
8 12345679*9 111111111 超长数字测试
9 3/5 0.6 结果为小数
10 3/0.6 5 输入为小数
11 (3-2)) ERROR_02 异常情况
12 (1++3) ERROR_02 异常情况
13 2/(5-5) ERROR_03 异常情况

要求:
1、实现栈的push、pop基本操作;
2、检测表达式的输入是否是正确的数学表达式;
3、对于正确的数学表达式求取其值。

请各位帮忙求解一下,主要是栈的应用。

题主可以看看这个,他的代码有问题,我给修改了下,主要功能都有,其他的可能需要你自己研究下了
https://ask.csdn.net/questions/7451896

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define INIT_STRING_SIZE 100
#define True 1
#define False 0
int saved_class[4] = {0, 0, 0, 0};
typedef struct aNum
{
    double data;
    char oper;
    int dataClass;
    int power;
    struct aNum *next;
} num;
typedef struct
{
    char *formula;
    int length;
} string;

void setNULL(char *num) //清空一个字符串
{
    int i = 0;
    while (i < 5)
    {
        num[i] = NULL;
        ++i;
    }
}
int countOperators(string *input, int *counter) // processing step 1
{                                               //计算运算符个数
    int i = 0;
    while (input->formula[i] != '\0')
    {
        switch (input->formula[i++])
        {
        case '+':
        case '-':
        case '*':
        case '/':
            ++counter;
            break;
        default:
            break;
        }
        ++input->length;
    }
    return 1;
}
int getData(string *input, num *nums) // processing step 2
{                                     //把数字,符号和class存入nums的结构体
    int i = 0;                        // counter of input->formula
    int k = 0;                        // counter of temp;
    int power = 0;
    char temp[5];
    int inBracket = False;
    num *p = nums;
    num *body;

    while (i <= input->length)
    {
        if ((input->formula[i] < '0' || input->formula[i] > '9') && input->formula[i] != '.' && input->formula[i] != '^')
        { //进入此处时数据已经收集完毕
            if (input->formula[i] == '(')
            {
                inBracket = True;
                ++i;
                continue;
            }
            if (input->formula[i] == ')')
            {
                inBracket = False;
                ++i;
                continue;
            }
            body = (num *)calloc(1, sizeof(num));

            body->data = atof(temp); //得到数字
            setNULL(temp);           //归零temp
            k = 0;

            switch (input->formula[i])
            {
            case '+':
                body->dataClass = inBracket == False ? 1 : 3; //计算当前运算符的等级
                ++saved_class[body->dataClass - 1];           //在等级数组里记录一次
                body->oper = input->formula[i];               //得到运算符
                break;

            case '-':
                body->dataClass = inBracket == False ? 1 : 3;
                ++saved_class[body->dataClass - 1];
                body->oper = input->formula[i];
                break;

            case 'x':
            case '*':
                body->dataClass = inBracket == False ? 2 : 4;
                ++saved_class[body->dataClass - 1];
                body->oper = input->formula[i];
                break;

            case '/':
                body->dataClass = inBracket == False ? 2 : 4;
                ++saved_class[body->dataClass - 1];
                body->oper = input->formula[i];
                break;

            default:
                break;
            }
            if (power != 0)
            {
                body->power = power;
                power = 0;
            }
            p->next = body;
            p = p->next;
        }
        else if (input->formula[i] == '^')
        {
            power = input->formula[++i] - 48;
        }
        else
        {
            temp[k++] = input->formula[i];
        }
        ++i;
    }
    return 1;
}
double compute(double num1, double num2, char opt)
{ //每次运算单独提取
    double result;
    switch (opt)
    {
    case '-':
        result = num1 - num2;
        break;
    case '+':
        result = num1 + num2;
        break;
    case 'x':
    case '*':
        result = num1 * num2;
        break;
    case '/':
        result = num1 / num2;
        break;
    }
    return result;
}
int processingData(num *nums) // processing step 3
{                             // nums作为头结点是没有数据的
    int s = 3;                // saved_class
    int i = 0;
    num *p = nums;
    num *p_front;
    while (saved_class[s] == 0 && s > 0)
        --s;
    while (p->next->next != NULL) // class oper next 都可以
    {
        if (p->next->dataClass != s + 1)
        {
            p = p->next;
            continue;
        }
        p_front = p;
        p = p->next; // p此时指向待计算的第一个struct aNUm
        if (p->power != 0)
        {
            p->data = pow(p->data, p->power);
            p->power = 0;
        }
        if (p->next->power != 0)
        {
            p->next->data = pow(p->next->data, p->next->power);
            p->next->power = 0;
        }
        p->next->data = compute(p->data, p->next->data, p->oper);

        p_front->next = p->next;
        free(p);
        --saved_class[s];
        while (saved_class[s] == 0 && s != 0)
            --s;
        p = nums;
    }
    if (nums->next->power != 0) //处理单个数字输入的情况,比如2^2
    {
        nums->next->data = pow(nums->next->data, nums->next->power);
    }

    printf("result=%lf\n", nums->next->data);
    return 1;
}
int main()
{
    int *counter = 0;
    num *nums = NULL;
    string *input;
    input = (string *)calloc(1, sizeof(string));
    input->formula = (char *)calloc(INIT_STRING_SIZE, sizeof(string));

    puts("Input formula:");
    scanf("%s", input->formula);

    //得到运算符和运算符个数
    countOperators(input, counter);
    //根据运算符个数申请存储数字的空间
    nums = (num *)calloc(1, sizeof(num));
    //存储数字和运算符
    getData(input, nums);
    processingData(nums);

    free(input->formula);
    free(input);
    free(nums->next);
    free(nums);
    system("pause"); //如果你是linux或者macos,可能需要去掉这句
    return 0;
}

考研考不到这么难,搞懂四则的求法就可以了

可以考虑参考一下以下代码的思路:


#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<stack>
#include<algorithm>
using namespace std;
string str;
int que[10000], len = 0;
int prior[300];
stack<char>sta;
int calus(int a, int b, char s)
{
    return s == '+' ? a + b : s == '-' ? a - b : s == '*' ? a * b : a / b;
}
int main()
{
    cout << "Input" << endl;
    prior['+'] = 1;
    prior['-'] = 1;
    prior['*'] = 2;
    prior['/'] = 2;
    while (sta.size() > 0)sta.pop();

     cin >> str;
        str = "(" + str + ")";
        for (int i = 0; i < str.length(); i++)
        {
            if (str[i] >= '0'&&str[i] <= '9')
            {
                int number = str[i] - '0';
                while (str[i + 1] >= '0'&&str[i + 1] <= '9') number = number * 10 + str[++i] - '0';

                que[len++] = number;
            }
            else
            {
                if (str[i] == '(') sta.push(str[i]);
                else if (str[i] == ')')
                {
                    while (sta.top() != '(')
                    {
                        len--;
                        que[len - 1] = calus(que[len - 1], que[len], sta.top());
                        sta.pop();
                    }
                    sta.pop();
                }
                else
                {
                    while (!sta.empty() && sta.top() != '('&&prior[sta.top()] >= prior[str[i]])
                    {
                        len--;
                        que[len - 1] = calus(que[len - 1], que[len], sta.top());
                        sta.pop();
                    }
                    sta.push(str[i]);
                }
            }
        }
        cout << "Output"<<endl;
        cout << que[--len] << endl;
        cout << "End" << endl;
//    }
    return 0;
}

文章链接:https://blog.csdn.net/Janchee/article/details/109532877

符合题目的要求加自测如下,实现栈操作和表达式求值。还有一些细节可以自己改改,下面是题目的测试,注意没有处理中间空格情况,所以输入不能有空格,要输入的话稍微过滤一下就行了
测试case 1:
1+2 *3
7
测试case 2:
1+2^3
9
测试case 3:
1+2/0.5
5.000000
测试case 4:
(2+3) *(3-1)^3
40
测试case 5:
(1+2
error_300

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MAX_SIZE 100

#define EXP_DATA_INVALID 0
#define EXP_DATA_DOUBLE 1
#define EXP_DATA_INT 2
#define EXP_DATA_OP 3

char legel_letter[] = "1234567890.[]()+-*/^ ";
char legel_op[] = "[(+-*/^";

typedef struct _exp_data {
    union {
        double d_d;
        int    i_d;
        char   op;
    } u;
    int type;
} exp_data;

typedef struct _stack {
    exp_data *data;
    int top;
    int size;
} stack;

void init(stack *s)
{
    s->data = (exp_data *)malloc(sizeof(exp_data) * MAX_SIZE);
    s->size = MAX_SIZE;
    s->top = -1;
}

int empty(stack *s)
{
    return s->top == -1;
}

exp_data top(stack *s)
{
    exp_data invalid;
    invalid.type = EXP_DATA_INVALID;
    if (empty(s))
        return invalid;
    return s->data[s->top];
}

int push(stack *s, exp_data val)
{
    if (s == NULL || s->top + 1 == s->size)
        return 0;
    s->top += 1;
    s->data[s->top] = val;
    return 1;
}

int pop(stack *s)
{
    if (s == NULL || empty(s))
        return 0;
    s->top -= 1;
    return 1;
}

int judge_oper(char *str, char letter)
{
    char sub[1] = {0};
    char *p;
    sub[0] = letter;
    sub[1] = '\0';
    if(( p = strstr(str, sub)) == NULL) return 0;
    else return 1;
}

int get_op_number(char *str, exp_data *val)
{
    int i = 0;
    int flag_d_d = 0;
    char d_d_i[100] = {0};

    for (; (str[i]>= '0' && str[i] <= '9') || str[i] == '.'; i++) {
        if (str[i] == '.') flag_d_d = 1;
        d_d_i[i] = str[i];
    }
    if (i > 0) {
        if (flag_d_d) {
            val->u.d_d = strtod (d_d_i, NULL);
            val->type = EXP_DATA_DOUBLE;
        } else {
            val->u.i_d = strtod (d_d_i, NULL);
            val->type = EXP_DATA_INT;
        }
    }
    return i;
}

void do_op_number(stack *s, exp_data  val)
{
    exp_data top_1;
    exp_data top_2;
    char op;
    int flag_d_oper1 = 0;
    int flag_d_oper2 = 0;
    double d_d;

    if(empty(s)) {push(s, val); return;}

    top_1 = top(s);
    if (top_1.type != EXP_DATA_OP) { printf("error_1\n"); return; }
    op = top_1.u.op;

    if (op == '(' || op == '[') { push(s, val); return;}

    pop(s);
    top_2 = top(s);
    if (top_2.type == EXP_DATA_INVALID || top_2.type == EXP_DATA_OP) { printf("error_1\n"); return;}
    pop(s);
    if (top_2.type == EXP_DATA_DOUBLE) flag_d_oper2 = 1;
    if (val.type == EXP_DATA_DOUBLE) flag_d_oper1 = 1;
    switch(op) {
        case '+':
            d_d = (flag_d_oper2 ? top_2.u.d_d : top_2.u.i_d) + (flag_d_oper1?val.u.d_d : val.u.i_d);
            break;
        case '-':
            d_d = (flag_d_oper2 ? top_2.u.d_d : top_2.u.i_d) - (flag_d_oper1?val.u.d_d : val.u.i_d);
            break;
        case '*':
            d_d = (flag_d_oper2 ? top_2.u.d_d : top_2.u.i_d) * (flag_d_oper1?val.u.d_d : val.u.i_d);
            break;
        case '/':
            if ((flag_d_oper1?val.u.d_d : val.u.i_d) == 0) { printf("error_3\n"); return;}
            d_d = (flag_d_oper2 ? top_2.u.d_d : top_2.u.i_d) / (flag_d_oper1?val.u.d_d : val.u.i_d);
            break;
        case '^':
            d_d = pow((flag_d_oper2 ? top_2.u.d_d : top_2.u.i_d) , (flag_d_oper1?val.u.d_d : val.u.i_d));
            break;
    }
    if(flag_d_oper1 || flag_d_oper2) {
        val.type = EXP_DATA_DOUBLE;
        val.u.d_d = d_d;
        push(s, val);
    } else {
        val.type = EXP_DATA_INT;
        val.u.i_d = (int)d_d;
        push(s, val);
    }
}

void do_op_brackets(stack *s, char letter)
{
    exp_data top_1;
    exp_data top_2;

    top_1 = top(s);
    pop(s);

    //do (1+2)
    do_op_number(s, top_1);

    //do remove (1) and restore 1 to stack
    top_1 = top(s);
    pop(s);
    top_2 = top(s);
    pop(s);
    push(s, top_1);

    if ( letter == ')' ) {
        if (top_2.type != EXP_DATA_OP || top_2.u.op != '(') {
            printf("error_3\n");
            return ;
        }
    }
    if ( letter == ']' ) {
        if (top_2.type != EXP_DATA_OP || top_2.u.op != '[') {
            printf("error_3\n");
            return ;
        }
    }
}

int need_compute(char cur_op, char pre_op)
{
    //if (pre_op == '(' || pre_op == '[') return 0;
    if (cur_op == '+' || cur_op == '-') return 1;
    if (cur_op == '*' || cur_op == '/') {
        if (pre_op == '+' || pre_op == '-') return 0;
        else return 1;
    }
    if (cur_op == '^') return 0;
    return 1;
}

void do_push_op_brackets(stack *s, char letter)
{
    exp_data val;
    val.type = EXP_DATA_OP;
    val.u.op = letter;
    exp_data top_1, top_2, top_3;
    if (empty(s) || letter == '(' || letter == '[' || letter == '^') {
        if (push(s, val) == 0) { printf("push brackets error\n"); }
        return;
    }
    while(!empty(s)) {
        top_1 = top(s);
        pop(s);
        if(empty(s)) { push(s, top_1); push(s, val); return;}
        top_2 = top(s);
        if(top_2.type == EXP_DATA_OP && (top_2.u.op == '(' || top_2.u.op == '[')) {
            push(s, top_1); push(s, val); return;
        }
        pop(s);
        if(empty(s)) { push(s, top_2); push(s, top_1); push(s, val); return;}
        top_3 = top(s);
        pop(s);
        if (top_2.type != EXP_DATA_OP) { printf("error_3\n"); return; }
        if (need_compute(letter, top_2.u.op)) {
            push(s, top_3); push(s, top_2);
            do_op_number(s, top_1);
        } else {
            push(s, top_3); push(s, top_2); push(s, top_1);
            push(s, val);
            return;
        }
    }
    push(s, val);
}

void do_compute(char *exp)
{
    stack s;
    exp_data val;
    int i = 0, jump = 0;
    char letter;
    init(&s);
    letter = exp[i];
    while(letter != '\0') {
        if (judge_oper(legel_letter, letter) == 0) { printf("error_0\n"); break;}
        if (judge_oper(legel_op, letter)) { do_push_op_brackets(&s, letter); }
        if (letter == ')' || letter == ']') { do_op_brackets(&s, letter); }
        if (letter == '.' && (i == 0 || exp[i-1] > '9' || exp[i-1] < '0')) {printf("error_00\n"); break;}
        if ((letter >= '0' && letter <= '9') || letter == '.') {
            jump = get_op_number(&exp[i], &val);
            if (!jump) { printf("error_000\n"); break;}
            push(&s, val);
            i+=jump;
            jump = 0;
        } else i++;
        letter = exp[i];
    }

    if(empty(&s)) { printf("error_30\n"); goto err; }

    exp_data top_1, top_2;
    while(!empty(&s) && s.top >= 2) {
        top_1 = top(&s);
        pop(&s);
        do_op_number(&s, top_1);
    }

    //do last result
    top_1 = top(&s);
    pop(&s);
    if (!empty(&s))  { printf("error_300\n"); goto err; }

    if  (top_1.type == EXP_DATA_OP) printf("error_3000\n");
    else {
        if (top_1.type == EXP_DATA_DOUBLE) printf("%lf\n", top_1.u.d_d);
        else printf("%d\n", top_1.u.i_d);
    }
err:
    if (s.data) free(s.data);
}

int main()
{
   char exp[100];
   scanf("%s", exp);
   do_compute(exp);
   return 0;
}

#include "stdio.h"

int n,i; /* 请注意这里的n与i设置为全局变量的用意 */

float val[100]; /* 这个数组用来收集字符流中的数 */

char c[1000],fu[100]; /* c数组是字符流,而fu数组用来收集计算符号+-* /和{、}*/

float digui()

{

float he=0,ji=0;  /* he代表加减运算结果,ji代表乘除运算结果 */

char hefu='+';    /* 每次进入递归是,都要把标示符he设置为0,hefu设置为+。但那个标示符ji可以不用设置 */



for( ;fu[i]!='}'&&fu[i]!='=';i++)

{

    switch(fu[i])

    {



        case '{':

        i++;

        digui();  // 如果遇到圆括号,则优先计算圆括号里面的内容

        break;

        

        

        

        case '+':

        if(hefu=='+') {val[n] = he + val[n];he = val[n];}  

        else          {val[n] = he - val[n],he = val[n];}  // 如果+、-后面的符号依然是加减,则可以进行计算

        hefu = '+';                                        

        n++;

        break;

        

        case '-':

        if(hefu=='+')  {val[n] = he + val[n];he = val[n];}  

        else           {val[n] = he - val[n];he = val[n];}  // 同上

        hefu = '-';

        n++;

        break;

        

        case '*':  //  如果遇到优先级高一级的乘符号【或除符号】,则进入循环,直至遇到非乘除符号时推出

        {

        ji=val[n];  // ji在这里被设置

        while(1)

        {

           if(fu[i] == '*')

           {

              if(fu[i+1] == '{')  //  如果在乘除循环里遇到圆括号,则递归调用自身,就是优先计算圆括号里面的内容

                {

                        i+=2;n++;

                        ji = ji * digui();

                }

              else

                {

                        ji = ji*val[n+1];

                        i++;n++;

                }

            }

            else if(fu[i] == '/')

            {

                if(fu[i+1] == '{')

                {

                        i+=2;n++;

                        ji = ji / digui();

                }

                else

                {

                        ji = ji/val[n+1];

                        i++;n++;

                }

            }

            else break;  // 遇到非乘除符号,退出

        }

        val[n] = ji;  // 乘除循环结束,把n现在指向的数设置成循环计算的结果数,以便它以后可以与he计算,最后得出前面所有数的运算结果

        if(fu[i]=='+'||fu[i]=='-')

        i--;

        break;

        }

        

        case '/':   //这个与上面那个case里面的作用一样

        {

            ji = val[n];

            while(1)

            {

                if(fu[i] == '*')

                {

                    if(fu[i+1] == '{')

                    {

                        i+=2;n++;

                        ji = ji * digui();

                    }

                    else

                    {

                        ji = ji*val[n+1];

                        i++;n++;

                    }

                }

                if(fu[i] == '/')

                {

                    if(fu[i+1] == '{')

                    {

                        i+=2;n++;

                        ji = ji / digui();

                        

                    }

                    else

                    {

                        ji = ji/val[n+1];

                        i++;n++;

                    }

                }

                else break;  

            }

        } 

        val[n] = ji;

        if(fu[i]=='+'||fu[i]=='-')

        i--;

        break;

        }

}



if(hefu == '+') val[n] = he + val[n];  // 到这里就是到了一个递归的结束,然后根据hefu的状态决定进行+运算或-运算

else val[n] = he - val[n];



return val[n];  // 最后我们需要返回这个值

}

void main()

{

int a=0,j=0;float b=0,d=0,g=10;;

gets(c);



for(i=0;c[i]!=0&&i<1000;i++)

{

    if(c[i]>='0'&&c[i]<='9')

    {

        

        while(c[i]>='0'&&c[i]<='9')

        {

            b=(c[i]-'0')+b*10;

            i++;

        }

        if(c[i]=='.')

        {

            i++;

            while(c[i]>='0'&&c[i]<='9')

            {

                d=d+(c[i]-'0')/g;

                g*=10;

                i++;

            }

        }  // 以上是手机输入流中的数

    val[n]=b+d;

    n++;

    }

  b=0;d=0;g=10;

}



for(i=0;c[i]!=0;i++)

    {

        if(c[i] < '0' || c[i] > '9')

        fu[j++]=c[i];

    }  // 这个则是收集输入流中的运算符


j=n;



i=0;

n=0;  // 这里的清零是必须的

printf(":::::%f\n", digui());

}

就是一个数学表达式的解析和结果计算,push和pop只是方法只有,实现的方法有很多种