作者:胡敬灏
#include <stdio.h>
#include <ctype.h> // 用于字符判断
#include <stdlib.h> // 用于exit函数
#define MAX_SIZE 100 // 栈的最大容量
/* 操作数栈结构(存储计算过程中的数值) */
typedef struct {
double data[MAX_SIZE]; // 存储数值的数组
int top; // 栈顶指针(-1表示空栈)
} OperandStack;
/* 运算符栈结构(存储运算符和括号) */
typedef struct {
char data[MAX_SIZE]; // 存储运算符的数组
int top; // 栈顶指针
} OperatorStack;
// 函数原型声明
void initOperandStack(OperandStack *s);
void pushOperand(OperandStack *s, double val);
double popOperand(OperandStack *s);
char peekOperator(OperatorStack *s);
int getPriority(char op);
double calculate(double a, double b, char op);
double evaluateExpression(const char *expr);
int main() {
const char *expr = "(3+5)*2-6/3"; // 测试表达式
double result = evaluateExpression(expr);
printf("表达式 %s 的结果是: %.2f\n", expr, result);
return 0;
}
/* 初始化操作数栈 */
void initOperandStack(OperandStack *s) {
s->top = -1; // 栈顶指针初始化为-1表示空栈
}
/* 操作数入栈 */
void pushOperand(OperandStack *s, double val) {
if (s->top >= MAX_SIZE - 1) {
printf("操作数栈溢出!");
exit(1);
}
s->data[++s->top] = val; // 栈顶指针先加1再存入数据
}
/* 操作数出栈 */
double popOperand(OperandStack *s) {
if (s->top < 0) {
printf("操作数栈为空!");
exit(1);
}
return s->data[s->top--]; // 返回栈顶数据后指针减1
}
/* 查看运算符栈顶元素 */
char peekOperator(OperatorStack *s) {
return s->data[s->top];
}
/* 获取运算符优先级 */
int getPriority(char op) {
switch(op) {
case '+': case '-': return 1; // 加减法优先级
case '*': case '/': return 2; // 乘除法优先级
case '(': return 0; // 括号特殊处理
default:
printf("非法运算符:%c", op);
exit(1);
}
}
/* 执行实际计算 */
double calculate(double a, double b, char op) {
switch(op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/':
if (b == 0) {
printf("除数不能为零!");
exit(1);
}
return a / b;
default:
printf("非法运算符:%c", op);
exit(1);
}
}
/* 核心表达式求值函数 */
double evaluateExpression(const char *expr) {
OperandStack numStack; // 操作数栈
OperatorStack opStack; // 运算符栈
initOperandStack(&numStack);
opStack.top = -1; // 初始化运算符栈
int i = 0;
while (expr[i] != '\0') {
// 情况1:处理数字(包括多位数)
if (isdigit(expr[i])) {
double num = 0;
while (isdigit(expr[i])) {
num = num * 10 + (expr[i] - '0'); // 数字位拼接
i++;
}
pushOperand(&numStack, num);
}
// 情况2:处理左括号
else if (expr[i] == '(') {
opStack.data[++opStack.top] = expr[i];
i++;
}
// 情况3:处理右括号
else if (expr[i] == ')') {
while (opStack.data[opStack.top] != '(') {
// 弹出括号内的运算符进行计算
char op = opStack.data[opStack.top--];
double b = popOperand(&numStack);
double a = popOperand(&numStack);
pushOperand(&numStack, calculate(a, b, op));
}
opStack.top--; // 弹出左括号
i++;
}
// 情况4:处理运算符
else if (expr[i] == '+' || expr[i] == '-' ||
expr[i] == '*' || expr[i] == '/') {
// 比较运算符优先级,执行栈内运算
while (opStack.top != -1 &&
getPriority(expr[i]) <= getPriority(opStack.data[opStack.top])) {
char op = opStack.data[opStack.top--];
double b = popOperand(&numStack);
double a = popOperand(&numStack);
pushOperand(&numStack, calculate(a, b, op));
}
opStack.data[++opStack.top] = expr[i]; // 当前运算符入栈
i++;
}
// 跳过空格等其他字符
else {
i++;
}
}
// 处理剩余运算符
while (opStack.top != -1) {
char op = opStack.data[opStack.top--];
double b = popOperand(&numStack);
double a = popOperand(&numStack);
pushOperand(&numStack, calculate(a, b, op));
}
return popOperand(&numStack);
}
心得:1.对两个栈的熟练使用,一个数字栈,一个字符栈
2.对字符的比较,利用Switch case 分类讨论 用数字123比较 并且可以在放入运算前有比较 是一个很好的思路
3.遇到一个新的字符时,先比较后,先进行运算再放入
4.这是一个对栈很综合的应用