Arrays 在计算不带括号的简单数学表达式时保持运算顺序
我正在用C语言创建一个计算器程序,它最多需要5个数字和4个运算,然后计算出答案,以此来更好地学习语言。我几乎所有的东西都工作正常,除了它还没有按照操作顺序。我能想到的唯一方法是,通过将乘法和除法语句移到数组的前面,将加法和减法语句移到数组的后面,以某种方式同时对运算和数字进行排序。然而,我完全不知道如何去做,我认为有一种更好、更有效的方法来完成这项任务,这是一个非常安全的假设。有更多C语言经验的人知道怎么做吗 这是我目前的代码:Arrays 在计算不带括号的简单数学表达式时保持运算顺序,arrays,c,sorting,operator-precedence,Arrays,C,Sorting,Operator Precedence,我正在用C语言创建一个计算器程序,它最多需要5个数字和4个运算,然后计算出答案,以此来更好地学习语言。我几乎所有的东西都工作正常,除了它还没有按照操作顺序。我能想到的唯一方法是,通过将乘法和除法语句移到数组的前面,将加法和减法语句移到数组的后面,以某种方式同时对运算和数字进行排序。然而,我完全不知道如何去做,我认为有一种更好、更有效的方法来完成这项任务,这是一个非常安全的假设。有更多C语言经验的人知道怎么做吗 这是我目前的代码: /* A calculator that accepts up t
/* A calculator that accepts up to 5 numbers and performs
multiple mathematical operations on the given numbers. */
#include <stdio.h>
#include <stdlib.h>
/* Creating functions for each of
the basic mathematical operators */
double add(double x, double y) {
/* Add variables x and y */
return x + y;
}
double subtract(double x, double y) {
/* Subtract variables x and y */
return x - y;
}
double multiply(double x, double y) {
/* Multiply variables x and y */
return x * y;
}
double divide(double x, double y) {
/* Divide variables x and y */
return x / y;
}
/* "operation" typedef to point
to the above operator functions */
typedef double (*operation)(double, double);
int main() {
double nums[5];
char operator;
operation operators[5]; // operator functions pointer array
double result;
int i = 0; // index variable to be used for iteration
printf("\n ################################\n");
printf(" ########## Calculator ##########\n");
printf(" ################################\n\n");
printf(" You may enter up to 5 numbers in you calculation.\n");
printf(" If you wish to enter fewer than 5 numbers, type an \"=\" as the operator after your final number.\n\n");
while (i < 5) {
// Getting the user's input
printf(" Enter a number: ");
scanf("%lf", &nums[i]);
if (i == 4) {
operators[i] = NULL; // Sets the final operator to NULL
} else {
printf(" Enter an operator (+, -, *, /, or =): ");
scanf(" %c", &operator);
/* Switch statement to decide which function to run on
the given numbers on each iteration through the loop */
switch(operator) {
case '+' :
operators[i] = add;
break;
case '-' :
operators[i] = subtract;
break;
case '*' :
operators[i] = multiply;
break;
case '/' :
operators[i] = divide;
break;
default :
operators[i] = NULL;
break;
}
}
if (!operators[i]) break; // Breaks out of the loop if the current operator is NULL
i++; // Increments the index variable up by 1
}
result = nums[0];
for (i = 1; i < 5; i++) {
if (operators[i - 1]) {
result = operators[i - 1](result, nums[i]);
} else {
break;
}
}
// Printing out the answer rounded to 2 decimal points
printf("Result: %.2f\n", result);
return 0;
}
下面是我希望它能提供的一个示例:
################################
##########计算器##########
################################
您最多可以在计算中输入5个数字。
如果希望输入少于5个数字,请在最终数字后键入“=”作为运算符。
输入一个数字:3
输入运算符(+、-、*、/、或=):+
输入一个数字:6
输入运算符(+、-、*、/、或=):-
输入一个数字:7
输入运算符(+、-、*、/、或=):*
输入一个数字:3
输入运算符(+、-、*、/、或=):/
输入一个数字:2
结果:-1.50
[以21.57秒完成]
任何人都能想到什么方法来实现这一点吗?如果表达式中不支持括号,问题将大大简化,您可以对输入表达式进行两次运算。这里的保证是表达式树的深度永远不会超过2级。第一个过程负责处理更高优先级的操作(乘法、除法),并确保这些操作以正确的符号完成。第二步只对剩下的部分进行加减运算
我假设参数可以被变异,表达式被正确地解析和验证,应用程序在零上除法,不处理溢出,为了简化而使用int,因此考虑这只是一个快速和肮脏的概念证明来显示两遍表达式求值技术。
#include <stdio.h>
enum {ADD, SUB, MUL, DIV};
int _add(int a, int b) {return a + b;}
int _sub(int a, int b) {return a - b;}
int _mul(int a, int b) {return a * b;}
int _div(int a, int b) {return a / b;}
int (*ops[4])(int x, int y) = {_add, _sub, _mul, _div};
int eval_math_expr_without_parens(int len, int *e) {
for (int i = 0; i < len - 2; i += 2) {
if (e[i+1] == SUB) {
e[i+1] = ADD;
e[i+2] *= -1;
}
if (e[i+1] == MUL || e[i+1] == DIV) {
e[i+2] = ops[e[i+1]](e[i], e[i+2]);
e[i+1] = ADD;
e[i] = 0;
}
}
for (int i = 0; i < len - 2; i += 2) {
e[i+2] = ops[e[i+1]](e[i], e[i+2]);
}
return len ? e[len-1] : 0;
}
int main() {
int lens[] = {3, 3, 5, 5, 9, 11, 11};
int exprs[][13] = {
{2, MUL, 5},
{2, ADD, 5},
{2, MUL, 5, ADD, 3},
{2, SUB, 5, MUL, 3},
{2, ADD, 5, MUL, 3, MUL, 2, SUB, 3},
{20, DIV, 5, ADD, 3, MUL, 2, SUB, 3, MUL, 4},
{20, SUB, 5, SUB, 3, SUB, 4, MUL, 2, SUB, 3, MUL, 4},
};
for (int i = 0; i < 7; i++) {
for (int j = 0; j < lens[i]; j++) {
if (j % 2) {
printf("%c", "+-*/"[exprs[i][j]]);
}
else {
printf("%d", exprs[i][j]);
}
}
printf("=%d\n", eval_math_expr_without_parens(lens[i], exprs[i]));
}
return 0;
}
如果您确实需要支持parens,那么您对树有任意的深度,而这种策略不会有帮助。当然,这是一个已解决的问题,因此请检查或仅将
bc
作为子进程运行,并捕获结果(速度慢但容易)。如果表达式中不支持括号,则问题将大大简化,您可以对输入表达式进行两次运算。这里的保证是表达式树的深度永远不会超过2级。第一个过程负责处理更高优先级的操作(乘法、除法),并确保这些操作以正确的符号完成。第二步只对剩下的部分进行加减运算
我假设参数可以被变异,表达式被正确地解析和验证,应用程序在零上除法,不处理溢出,为了简化而使用int,因此考虑这只是一个快速和肮脏的概念证明来显示两遍表达式求值技术。
#include <stdio.h>
enum {ADD, SUB, MUL, DIV};
int _add(int a, int b) {return a + b;}
int _sub(int a, int b) {return a - b;}
int _mul(int a, int b) {return a * b;}
int _div(int a, int b) {return a / b;}
int (*ops[4])(int x, int y) = {_add, _sub, _mul, _div};
int eval_math_expr_without_parens(int len, int *e) {
for (int i = 0; i < len - 2; i += 2) {
if (e[i+1] == SUB) {
e[i+1] = ADD;
e[i+2] *= -1;
}
if (e[i+1] == MUL || e[i+1] == DIV) {
e[i+2] = ops[e[i+1]](e[i], e[i+2]);
e[i+1] = ADD;
e[i] = 0;
}
}
for (int i = 0; i < len - 2; i += 2) {
e[i+2] = ops[e[i+1]](e[i], e[i+2]);
}
return len ? e[len-1] : 0;
}
int main() {
int lens[] = {3, 3, 5, 5, 9, 11, 11};
int exprs[][13] = {
{2, MUL, 5},
{2, ADD, 5},
{2, MUL, 5, ADD, 3},
{2, SUB, 5, MUL, 3},
{2, ADD, 5, MUL, 3, MUL, 2, SUB, 3},
{20, DIV, 5, ADD, 3, MUL, 2, SUB, 3, MUL, 4},
{20, SUB, 5, SUB, 3, SUB, 4, MUL, 2, SUB, 3, MUL, 4},
};
for (int i = 0; i < 7; i++) {
for (int j = 0; j < lens[i]; j++) {
if (j % 2) {
printf("%c", "+-*/"[exprs[i][j]]);
}
else {
printf("%d", exprs[i][j]);
}
}
printf("=%d\n", eval_math_expr_without_parens(lens[i], exprs[i]));
}
return 0;
}
如果您确实需要支持parens,那么您对树有任意的深度,而这种策略不会有帮助。当然,这是一个已解决的问题,所以检查一下或只是运行<代码> BC/<代码>作为子过程并捕获结果(缓慢但容易)。我对C还是相当陌生,我还不知道它是如何工作的。它可能超出了您的问题范围,因为它相当复杂,但YouTube视频和文章可以解释这种实现计算器的特殊方法。如果您不支持parens,请迭代并计算所有高优先级运算,然后进行第二次传递并计算所有低优先级运算。如果涉及Paren,可以尝试调车场算法。或者只需将
bc
作为子进程运行;-)您可能会考虑使用堆栈转换中缀表示法来反转波兰。您能举个例子说明我是如何做到这一点的吗?我对C还是相当陌生,我还不知道它是如何工作的。它可能超出了您的问题范围,因为它相当复杂,但YouTube视频和文章可以解释这种实现计算器的特殊方法。如果您不支持parens,请迭代并计算所有高优先级运算,然后进行第二次传递并计算所有低优先级运算。如果涉及Paren,可以尝试调车场算法。或者只需将bc
作为子进程运行;-)