任务描述
本关任务:编写一个能计算表达式值的小程序。
相关知识
为了完成本关任务,你需要掌握:1.栈的封装,2.字符串的遍历,3,表达式求值的原理。
测试说明
平台会对你编写的代码进行测试:
输入由1行组成,包含表达式字符串 预期输出:表达式的值,3位小数
测试输入:3+2*5
预期输出:13.000
涉及浮点数,负数,以及数的n次幂。
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#include<string.h>
//创建字符栈
typedef struct Node {
int data;
struct Node* next;
} Node;
typedef struct Stack {
Node* top;
} Stack;
//创建数字栈(所有有关数字的出栈入栈等操作我都只是在前面加了一个n,表示数字....有点懒得打复杂的英文)
typedef struct nNode {
double data;
struct nNode* next;
} nNode;
typedef struct nStack {
nNode* top;
} nStack;
//判断是否是操作符,后面对遍历表达式有用
int is_operator(char ch) {
return (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^');
}
//如果是操作符,给各个操作符一个返回值,用来比较操作符的优先等级
int priority(char op) {
switch (op) {
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '^':
return 3;
default:
return 0;
}
}
//对弹出的两个数计算
double calculate(double a, char op, double b) {
switch (op) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return a / b;
case '^':
return pow(a, b);
default:
exit(1);
}
}
Stack* create_stack() { // 创建空栈
Stack* stack = (Stack*)malloc(sizeof(Stack));
stack->top = NULL;
return stack;
}
nStack* ncreate_stack() { // 创建空栈n
nStack* nstack = (nStack*)malloc(sizeof(nStack));
nstack->top = NULL;
return nstack;
}
void push(Stack* stack, int data) { // 入栈操作
Node* node = (Node*)malloc(sizeof(Node));
node->data = data;
node->next = stack->top;
stack->top = node;
}
//前面有n的都是对数字进行的操作,别看岔看重复了
void npush(nStack* stack, double data) { // 入栈操作n
nNode* nnode = (nNode*)malloc(sizeof(nNode));
nnode->data = data;
nnode->next = stack->top;
stack->top = nnode;
}
int pop(Stack* stack) { // 出栈操作
if (stack->top == NULL) {
return -1; // 如果栈为空,则返回-1
}
Node* node = stack->top;
int data = node->data;
stack->top = node->next;
free(node);
return data;
}
double npop(nStack* stack) { // 出栈操作n
if (stack->top == NULL) {
return -1; // 如果栈为空,则返回-1
}
nNode* node = stack->top;
double data = node->data;
stack->top = node->next;
free(node);
return data;
}
int top(Stack* stack) { // 返回栈顶元素
if (stack->top == NULL) {
return -1; // 如果栈为空,则返回-1
}
return stack->top->data;
}
double ntop(nStack* stack) { // 返回栈顶元素n
if (stack->top == NULL) {
return -1; // 如果栈为空,则返回-1
}
return stack->top->data;
}
//开始读取表达式expression,并且计算
double evaluate_expression(char* expression) {
nStack* s1 = ncreate_stack(); // 操作数栈,用于存储操作数
Stack* s2 = create_stack(); // 操作符栈,用于存储操作符
char n[10];//考虑到有浮点数的存在,需要建立一个char[]来存放浮点数的各个数字和小数点,然后调用atof函数可以转换为浮点数,之后入栈。
double num;//调用atof函数后用来存放浮点数。
int len = strlen(expression);
for (int i = 0, j = 0; i < len; i++) {
if (i == 0 && expression[i] == '-') {//第一个数字为负数时,也将第一个负号存放在n[]里,atof会转化为负数.
n[j] = expression[i];
j++;i++;
}
if ((expression[i] >= '0' && expression[i] <= '9') || expression[i] == '.') {// 如果当前字符为数字
n[j] = expression[i];
j++;
if (i == len - 1 || !(expression[i + 1] >= '0' && expression[i + 1] <= '9' || expression[i + 1] == '.')) {//一直读取到后面的数不是数字时
num = atof(n);
npush(s1, num);
for (int k = 0;k < j;k++) {
n[k] = 0;
}
j = 0;
}
}
else if (is_operator(expression[i])) { // 如果当前字符为操作符
while (s2->top != NULL && priority(top(s2)) >= priority(expression[i])) {
// 如果操作符栈不为空,并且栈顶操作符的优先级大于等于当前操作符的优先级
double b = npop(s1); // 出栈一个操作数作为运算的右操作数
double a = npop(s1); // 再出栈一个操作数作为运算的左操作数
char op = pop(s2); // 出栈一个操作符
double result = calculate(a, op, b); // 计算两个操作数和操作符的结果
npush(s1, result); // 将计算结果入栈到操作数栈中
}
push(s2, expression[i]); // 当前操作符入栈到操作符栈中
}
else if (expression[i] == '(') { // 如果当前字符为左括号
push(s2, expression[i]); // 入栈到操作符栈中
}
else if (expression[i] == ')') { // 如果当前字符为右括号
while (top(s2) != '(') { // 循环执行直到遇到左括号
double b = npop(s1); // 出栈一个操作数作为运算的右操作数
double a = npop(s1); // 再出栈一个操作数作为运算的左操作数
char op = pop(s2); // 出栈一个操作符
double result = calculate(a, op, b); // 计算两个操作数和操作符的结果
npush(s1, result); // 将计算结果入栈到操作数栈中
}
pop(s2); // 弹出左括号
}
}
// 处理剩余的操作符
while (s2->top != NULL) {
double b = npop(s1); // 出栈一个操作数作为运算的右操作数
double a = npop(s1); // 再出栈一个操作数作为运算的左操作数
char op = pop(s2); // 出栈一个操作符
double result = calculate(a, op, b); // 计算两个操作数和操作符的结果
npush(s1, result); // 将计算结果入栈到操作数栈中
}
return npop(s1); // 返回最终的计算结果
}
int main() {
char expression[100];
scanf("%s", expression);
double result = evaluate_expression(expression);
printf("%.3f\n", result);
return 0;
}