
如何用C语言实现带括号的四则运算
要在C语言中实现带括号的四则运算,关键在于理解表达式解析、栈的应用、逆波兰表达式(RPN)。本文将详细讨论这些方法,并提供一个完整的实现。
理解表达式解析
实现带括号的四则运算的核心在于解析表达式。解析表达式的过程主要包括两个步骤:将中缀表达式转换为后缀表达式(逆波兰表达式),然后计算后缀表达式的值。
栈的应用
栈在表达式解析中起到非常重要的作用。主要用在以下两个方面:1)在转换中缀表达式为后缀表达式时,用栈来暂存运算符和括号;2)在计算后缀表达式时,用栈来暂存操作数。
逆波兰表达式(RPN)
逆波兰表达式是一种将运算符放在操作数之后的表示方法。它的好处是消除了括号的使用,并且计算机可以非常方便地进行解析和计算。
一、表达式解析
在实现带括号的四则运算时,首先需要解析输入的数学表达式。解析表达式的主要目的是将中缀表达式转换为后缀表达式(RPN)。这一步骤需要使用栈来暂存操作符和括号。
1. 中缀表达式转换为后缀表达式
中缀表达式是我们日常使用的表达式形式(例如,3 + 4 * (2 - 1))。在这种形式中,运算符位于操作数之间。为了方便计算机处理,我们需要将中缀表达式转换为后缀表达式。
步骤:
-
初始化两个栈:一个用于存储操作符(operator stack),另一个用于存储输出的后缀表达式(output stack)。
-
从左到右扫描中缀表达式:
- 如果是操作数,直接压入输出栈。
- 如果是左括号
(,压入操作符栈。 - 如果是右括号
),弹出操作符栈中的操作符,直到遇到左括号,并将这些操作符压入输出栈。 - 如果是操作符,弹出操作符栈中优先级高于或等于当前操作符的所有操作符,将它们压入输出栈,然后将当前操作符压入操作符栈。
-
扫描结束后,将操作符栈中剩余的所有操作符压入输出栈。
2. 优先级处理
在转换过程中,需要处理操作符的优先级。通常,乘法和除法的优先级高于加法和减法。
// C语言中实现操作符优先级判断
int precedence(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
return 0;
}
二、计算后缀表达式
后缀表达式(RPN)的计算相对简单。只需要扫描后缀表达式中的每个元素:
- 如果是操作数,压入栈中。
- 如果是操作符,从栈中弹出相应数量的操作数,进行计算,并将结果压入栈中。
最终,栈中剩下的唯一元素就是计算结果。
三、完整代码实现
下面是一个完整的C语言代码示例,展示如何实现带括号的四则运算。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
// 栈的实现
typedef struct {
int top;
unsigned capacity;
int* array;
} Stack;
// 创建栈
Stack* createStack(unsigned capacity) {
Stack* stack = (Stack*) malloc(sizeof(Stack));
stack->capacity = capacity;
stack->top = -1;
stack->array = (int*) malloc(stack->capacity * sizeof(int));
return stack;
}
// 栈是否为空
int isEmpty(Stack* stack) {
return stack->top == -1;
}
// 栈是否满
int isFull(Stack* stack) {
return stack->top == stack->capacity - 1;
}
// 入栈
void push(Stack* stack, int item) {
if (isFull(stack)) return;
stack->array[++stack->top] = item;
}
// 出栈
int pop(Stack* stack) {
if (isEmpty(stack)) return -1;
return stack->array[stack->top--];
}
// 查看栈顶
int peek(Stack* stack) {
if (isEmpty(stack)) return -1;
return stack->array[stack->top];
}
// 判断是否为操作符
int isOperator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
}
// 判断优先级
int precedence(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
return 0;
}
// 中缀表达式转后缀表达式
void infixToPostfix(char* exp, char* output) {
int i, k = 0;
Stack* stack = createStack(strlen(exp));
if (!stack) return;
for (i = 0; exp[i]; ++i) {
if (isdigit(exp[i])) {
output[k++] = exp[i];
} else if (exp[i] == '(') {
push(stack, exp[i]);
} else if (exp[i] == ')') {
while (!isEmpty(stack) && peek(stack) != '(')
output[k++] = pop(stack);
pop(stack);
} else if (isOperator(exp[i])) {
while (!isEmpty(stack) && precedence(peek(stack)) >= precedence(exp[i]))
output[k++] = pop(stack);
push(stack, exp[i]);
}
}
while (!isEmpty(stack))
output[k++] = pop(stack);
output[k] = '