当前位置:   article > 正文

数据结构实训:表达式求值器(非常详细)_表达式求值器问题描述:设计一个表达式求值器,能够解析和计算由数字、运算符和括号

表达式求值器问题描述:设计一个表达式求值器,能够解析和计算由数字、运算符和括号

表达式求值器

问题描述:

设计一个表达式求值器,能够解析和计算由数字、运算符和括号组成的算术表达式。要求实现基本的四则运算,如加、减、乘、除并处理运算符的优先级和括号

设计要点:

1. 使用栈作为数据结构来处理运算符和操作数的优先级

2. 实现表达式的解析算法,将输入的字符串转换为内部表示形式,如逆波兰表示法。

3. 设计求值算法,根据运算符的优先级和操作数的顺序进行计算。

完整代码(超详细)

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4. #include <string.h>
  5. #define MAX 100
  6. typedef struct {
  7. int top;
  8. char items[MAX];
  9. } Stack;
  10. void initStack(Stack* s) {
  11. s->top = -1;
  12. }
  13. int isEmpty(Stack* s) {
  14. return (s->top == -1);
  15. }
  16. int isFull(Stack* s) {
  17. return (s->top == MAX - 1);
  18. }
  19. void push(Stack* s, char value) {
  20. if (!isFull(s)) {
  21. s->items[++(s->top)] = value;
  22. }
  23. else {
  24. printf("栈满了\n");
  25. }
  26. }
  27. char pop(Stack* s) {
  28. if (!isEmpty(s)) {
  29. return s->items[(s->top)--];
  30. }
  31. else {
  32. printf("栈为空\n");
  33. return 0;
  34. }
  35. }
  36. char peek(Stack* s) {
  37. if (!isEmpty(s)) {
  38. return s->items[s->top];
  39. }
  40. else {
  41. return '\0';
  42. }
  43. }
  44. int precedence(char op) {
  45. switch (op) {
  46. case '+':
  47. case '-':
  48. return 1;
  49. case '*':
  50. case '/':
  51. return 2;
  52. default:
  53. return 0;
  54. }
  55. }
  56. int isOperator(char ch) {
  57. return (ch == '+' || ch == '-' || ch == '*' || ch == '/');
  58. }
  59. void infixToPostfix(char* infix, char* postfix) {
  60. Stack s;
  61. initStack(&s);
  62. int k = 0;
  63. for (int i = 0; infix[i] != '\0'; i++) {
  64. if (isdigit(infix[i])) {
  65. while (isdigit(infix[i])) {
  66. postfix[k++] = infix[i++];
  67. }
  68. postfix[k++] = ' ';
  69. i--;
  70. }
  71. else if (infix[i] == '(') {
  72. push(&s, infix[i]);
  73. }
  74. else if (infix[i] == ')') {
  75. while (!isEmpty(&s) && peek(&s) != '(') {
  76. postfix[k++] = pop(&s);
  77. postfix[k++] = ' ';
  78. }
  79. pop(&s);
  80. }
  81. else if (isOperator(infix[i])) {
  82. while (!isEmpty(&s) && precedence(peek(&s)) >= precedence(infix[i])) {
  83. postfix[k++] = pop(&s);
  84. postfix[k++] = ' ';
  85. }
  86. push(&s, infix[i]);
  87. }
  88. }
  89. while (!isEmpty(&s)) {
  90. postfix[k++] = pop(&s);
  91. postfix[k++] = ' ';
  92. }
  93. postfix[k - 1] = '\0';
  94. }
  95. int evaluatePostfix(char* postfix) {
  96. Stack s;
  97. initStack(&s);
  98. int i = 0;
  99. while (postfix[i] != '\0') {
  100. if (isdigit(postfix[i])) {
  101. int num = 0;
  102. while (isdigit(postfix[i])) {
  103. num = num * 10 + (postfix[i++] - '0');
  104. }
  105. push(&s, num);
  106. }
  107. else if (isOperator(postfix[i])) {
  108. int val2 = pop(&s);
  109. int val1 = pop(&s);
  110. switch (postfix[i]) {
  111. case '+': push(&s, val1 + val2); break;
  112. case '-': push(&s, val1 - val2); break;
  113. case '*': push(&s, val1 * val2); break;
  114. case '/': push(&s, val1 / val2); break;
  115. }
  116. i++;
  117. }
  118. else {
  119. i++;
  120. }
  121. }
  122. return pop(&s);
  123. }
  124. int main() {
  125. char infix[MAX], postfix[MAX];
  126. printf("Enter an infix expression: ");
  127. fgets(infix, MAX, stdin);
  128. infix[strcspn(infix, "\n")] = '\0';
  129. infixToPostfix(infix, postfix);
  130. printf("Postfix expression: %s\n", postfix);
  131. int result = evaluatePostfix(postfix);
  132. printf("Result: %d\n", result);
  133. return 0;
  134. }

代码解释(主要看这个) 

 1.栈的实现

 typedef struct {

int top;

char items[MAX];

} Stack;

这里定义了一个结构体 Stack,它包含一个整数 top 用于指示栈顶位置,以及一个字符数组 items 作为栈的存储空间

  • initStack: 初始化栈,将 top 设置为 -1 表示栈为空。
  • isEmpty: 检查栈是否为空。
  • isFull: 检查栈是否已满。
  • push: 入栈操作,如果栈未满,将元素压入栈顶。
  • pop: 出栈操作,如果栈非空,弹出并返回栈顶元素。
  • peek: 查看栈顶元素,但不移除。

 2. 运算符优先级和判断

int precedence(char op) {
    switch (op) {
        case '+':
        case '-':
            return 1;
        case '*':
        case '/':
            return 2;
        default:
            return 0;
    }
}

int isOperator(char ch) {
    return (ch == '+' || ch == '-' || ch == '*' || ch == '/');
}

  • precedence: 返回运算符的优先级,+ 和 - 优先级较低(返回1),* 和 / 优先级较高(返回2),其他情况返回0。
  • isOperator: 判断字符是否为运算符。

3. 中缀转后缀表达式

void infixToPostfix(char* infix, char* postfix) {
    Stack s;
    initStack(&s);
    int k = 0;

    for (int i = 0; infix[i] != '\0'; i++) {
        if (isdigit(infix[i])) {
            while (isdigit(infix[i])) {
                postfix[k++] = infix[i++];
            }
            postfix[k++] = ' '; // 添加空格作为后缀表达式元素的分隔符
            i--; // 退回到数字的最后一个字符
        } else if (infix[i] == '(') {
            push(&s, infix[i]);
        } else if (infix[i] == ')') {
            while (!isEmpty(&s) && peek(&s) != '(') {
                postfix[k++] = pop(&s);
                postfix[k++] = ' ';
            }
            pop(&s); // 弹出 '('
        } else if (isOperator(infix[i])) {
            while (!isEmpty(&s) && precedence(peek(&s)) >= precedence(infix[i])) {
                postfix[k++] = pop(&s);
                postfix[k++] = ' ';
            }
            push(&s, infix[i]);
        }
    }

    // 将栈中剩余的运算符弹出并添加到后缀表达式中
    while (!isEmpty(&s)) {
        postfix[k++] = pop(&s);
        postfix[k++] = ' ';
    }
    postfix[k-1] = '\0'; // 移除最后一个空格,并添加字符串结束符
}

  • infixToPostfix: 将中缀表达式转换为后缀表达式。遍历中缀表达式,根据操作数、运算符和括号进行处理,并使用栈来管理运算符的顺序。

4. 后缀表达式求值

int evaluatePostfix(char* postfix) {
    Stack s;
    initStack(&s);
    int i = 0;
    while (postfix[i] != '\0') {
        if (isdigit(postfix[i])) {
            int num = 0;
            while (isdigit(postfix[i])) {

//这段代码用于解析并提取后缀表达式(即逆波兰表达式)中的数字
                num = num * 10 + (postfix[i++] - '0');

            }
            push(&s, num);
        } else if (isOperator(postfix[i])) {
            int val2 = pop(&s);
            int val1 = pop(&s);
            switch (postfix[i]) {
                case '+': push(&s, val1 + val2); break;
                case '-': push(&s, val1 - val2); break;
                case '*': push(&s, val1 * val2); break;
                case '/': push(&s, val1 / val2); break;
            }
            i++;
        } else {
            i++; // 跳过空格
        }
    }
    return pop(&s); // 返回最终的计算结果
}

num = num * 10 + (postfix[i++] - '0');详细解释
  1. isdigit(postfix[i]):

    • isdigit 是一个标准库函数,用于检查给定字符是否为数字字符('0' 到 '9')。如果 postfix[i] 是数字字符,则返回非零值,否则返回零。
    • postfix[i] 是当前正在处理的字符。
  2. num = num * 10 + (postfix[i++] - '0');:

    • num 是用来存储最终解析出的整数的变量。
    • postfix[i++] - '0'
      • postfix[i] 是当前的数字字符。
      • 减去字符 '0' 将字符转换为对应的整数值。例如,字符 '7' 减去 '0' 的 ASCII 值等于整数 7。
      • i++ 是后置递增操作,表示在使用 postfix[i] 之后,再将 i 增加 1,以便指向下一个字符。
    • num = num * 10 + ...
      • 每次循环中,将新的数字字符与之前解析的部分组合起来。
      • 例如,如果之前 num 是 12,现在读取到一个新的数字字符 '3',那么计算 num = 12 * 10 + 3 结果为 123。

  • evaluatePostfix: 对后缀表达式进行求值。遍历后缀表达式,遇到操作数则压入栈中,遇到运算符则弹出栈顶的两个操作数进行运算,并将结果压回栈中,直到表达式结束。

 5. 主函数

int main() {
    char infix[MAX], postfix[MAX];
    printf("Enter an infix expression: ");
    fgets(infix, MAX, stdin);
    infix[strcspn(infix, "\n")] = '\0'; // 去除末尾的换行符

    infixToPostfix(infix, postfix);
    printf("Postfix expression: %s\n", postfix);

    int result = evaluatePostfix(postfix);
    printf("Result: %d\n", result);

    return 0;
}

  • 主函数负责接收用户输入的中缀表达式,调用 infixToPostfix 转换为后缀表达式,然后调用 evaluatePostfix 计算结果并输出。

这些代码组合在一起实现了一个基本的表达式求值器,仅可以处理加减乘除四则运算和括号。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/770399
推荐阅读
相关标签
  

闽ICP备14008679号