#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <stdbool.h>
#define INIT_SIZE 100
#define INCRE_SIZE 10
#define OPERAND 1
#define OPERATOR 2
char _BUFFER[1000];
int _POS;
char myGetchar();
void myUnGetchar(char c);
typedef enum operator_et
{
LBR,
RBR,
ADD,
SUB,
MUL,
DIV,
INV,
SIN,
COS,
END
}operator_et;
typedef double data_t;
typedef struct cal_t
{
data_t *operand;
int *operator;
int operand_size;
int operator_size;
int operand_top;
int operator_top;
}cal_t;
typedef cal_t* cal_pt;
cal_pt calInit();
void calFree(cal_pt cal);
void calOperatorPush(operator_et operator, cal_pt cal);
operator_et calOperatorPop(cal_pt cal);
void calOperandPush(data_t operand, cal_pt cal);
data_t calOperandPop(cal_pt cal);
int operatorCmp(operator_et top, operator_et op);
void work(operator_et op, cal_pt cal);
int getop(char *op);
void calculator(cal_pt cal);
void __calculator(operator_et op, cal_pt cal);
int main()
{
cal_pt cal = calInit();
scanf("%s", _BUFFER);
_POS = 0;
calculator(cal);
printf("%.3lf\n", calOperandPop(cal));
calFree(cal);
return 0;
}
void __calculator(operator_et op, cal_pt cal)
{
switch(operatorCmp(cal->operator[cal->operator_top], op))
{
case 1:
{
calOperatorPush(op, cal);
break;
}
case -1:
{
do
{
work(calOperatorPop(cal), cal);
}while(operatorCmp(cal->operator[cal->operator_top], op) == -1);
__calculator(op, cal);
break;
}
case 0:
{
calOperatorPop(cal);
break;
}
}
}
char myGetchar()
{
return _BUFFER[_POS ++];
}
void myUnGetchar(char c)
{
_POS -= 1;
}
void calculator(cal_pt cal)
{
bool isOver = false;
char opString[20];
int type;
while (!isOver)
{
type = getop(opString);
if (type == OPERAND)
{
calOperandPush(atoi(opString), cal);
}
else
{
switch(opString[0])
{
case '+':
{
__calculator(ADD, cal);
break;
}
case '-':
{
__calculator(SUB, cal);
break;
}
case '*':
{
__calculator(MUL, cal);
break;
}
case '/':
{
__calculator(DIV, cal);
break;
}
case '^':
{
__calculator(INV, cal);
break;
}
case 'c':
{
__calculator(COS, cal);
break;
}
case 's':
{
__calculator(SIN, cal);
break;
}
case '(':
{
__calculator(LBR, cal);
break;
}
case ')':
{
__calculator(RBR, cal);
break;
}
case '#':
{
isOver = true;
__calculator(END, cal);
break;
}
}
}
}
}
int getop(char *op)
{
int pos = 0;
char c = myGetchar();
while (isblank(c))
{
c = myGetchar();
}
if (isdigit(c))
{
while (isdigit(c))
{
op[pos ++] = c;
c = myGetchar();
}
myUnGetchar(c);
op[pos] = '\0';
return OPERAND;
}
op[pos ++] = c;
op[pos] = '\0';
if (op[0] == 'c' || op[0] == 's')
{
myGetchar();
myGetchar();
}
return OPERATOR;
}
void work(operator_et op, cal_pt cal)
{
switch(op)
{
case ADD:
{
calOperandPush(calOperandPop(cal) + calOperandPop(cal), cal);
break;
}
case SUB:
{
data_t tmp = calOperandPop(cal);
calOperandPush(calOperandPop(cal) - tmp, cal);
break;
}
case MUL:
{
calOperandPush(calOperandPop(cal) * calOperandPop(cal), cal);
break;
}
case DIV:
{
data_t tmp = calOperandPop(cal);
calOperandPush(calOperandPop(cal) / tmp, cal);
break;
}
case INV:
{
data_t tmp = calOperandPop(cal);
calOperandPush(pow(calOperandPop(cal), tmp), cal);
break;
}
case SIN:
{
calOperandPush(sin(calOperandPop(cal)), cal);
break;
}
case COS:
{
calOperandPush(cos(calOperandPop(cal)), cal);
}
}
}
int operatorCmp(operator_et top, operator_et op)
{
int res;
switch(op)
{
case LBR:
{
res = 1;
break;
}
case RBR:
{
res = (top == LBR) ? 0 : -1;
break;
}
case END:
{
if (top == LBR)
{
fprintf(stderr, "wrong Input!\n");
exit(-1);
}
res = (top == END) ? 0 : -1;
break;
}
case ADD:
case SUB:
{
res = (top == END || top == LBR) ? 1 : -1;
break;
}
case MUL:
case DIV:
{
return (top == END || top == LBR || top == ADD || top == SUB) ? 1 : -1;
break;
}
case INV:
{
res = (top == COS || top == SIN || top == INV) ? -1 : 1;
break;
}
case COS:
case SIN:
{
res = (top == COS || top == SIN) ? -1 : 1;
break;
}
}
return res;
}
data_t calOperandPop(cal_pt cal)
{
return *(cal->operand + cal->operand_top --);
}
void calOperandPush(data_t operand, cal_pt cal)
{
if (++ cal->operand_top >= cal->operand_size)
{
cal->operand_size += INIT_SIZE;
cal->operand = (data_t *)realloc(cal->operand, sizeof(data_t) * cal->operand_size);
}
*(cal->operand + cal->operand_top) = operand;
}
operator_et calOperatorPop(cal_pt cal)
{
return *(cal->operator + cal->operator_top --);
}
void calOperatorPush(operator_et operator, cal_pt cal)
{
if (++ cal->operator_top >= cal->operator_size)
{
cal->operator_size += INCRE_SIZE;
cal->operator = (int *)realloc(cal->operator, sizeof(int) * cal->operator_size);
}
*(cal->operator + cal->operator_top) = operator;
}
void calFree(cal_pt cal)
{
free(cal->operator);
free(cal->operand);
cal->operator = NULL;
cal->operand = NULL;
cal->operator_size = cal->operand_size = 0;
cal->operator_top = cal->operand_top = -1;
}
cal_pt calInit()
{
cal_pt cal = (cal_pt)malloc(sizeof(cal_t));
cal->operator_size = cal->operand_size = INIT_SIZE;
cal->operator_top = cal->operand_top = -1;
cal->operator = (int*)malloc(sizeof(int) * INIT_SIZE);
cal->operand = (data_t *)malloc(sizeof(data_t) * INIT_SIZE);
calOperatorPush(END, cal);
return cal;
}
代码解释
首先,建立一个全局字符串数组BUFFUR,以便进行字符串操作
其次,建立两个栈:操作数栈与操作符栈
总体的流程如下:
- 取出一个操作数或操作符,
- 如果是操作数,则直接压入操作数栈
- 如果是操作符,与栈顶元素进行优先级比较(操作符栈在初始化时加入了一个结束符
#
方便计算) - 若新操作符的优先级更大,则压入栈
- 若新操作符的优先级更小,则将栈顶元素弹出进行运算,然后再回到第三步
- 若新操作符的优先级等于栈顶元素,则弹出栈顶元素(不进行运算)
- 回到1,直至取到
#
,执行最后一次操作、清空操作符栈后结束
优先级比较的规则:
- 总体优先级(从低到高):结束符
#
,加减法,乘除法,乘方运算,三角函数运算 - 当栈顶元素与新操作符优先级相同时,除非新元素为括号或
#
,否则默认新操作符的优先级更低 - 当栈顶元素为左括号时,除了右括号优先级与其相同外,任何操作符优先级均高于栈顶元素。若碰到结束符
#
,则说明输入括号不匹配,报错退出 - 当新元素为左括号时,默认其优先级高于任何运算符
- 当新元素为右括号时,默认其优先级低于除了左括号外的任何运算符
举例:70+cos(3+2/2/3^2-1)*(4-3)#
操作符栈事先加入了一个#
方便计算
- 取操作数70,压入栈,操作数栈:
70
- 取操作符
+
,优先级高于#
,压入栈,此时操作符栈:#, +
- 取操作符
cos
,优先级高于+
,压入栈,此时操作符栈:#, +, cos
- 取操作符
(
,默认优先级高于任何操作符,压入栈,此时操作符栈:#, +, cos, (
- 取操作数3,压入栈,操作数栈:
70, 3
- 取操作符
+
,默认优先级高于栈顶元素(
,压入栈,此时操作符栈:#, +, cos, (, +
- 取操作数2,压入栈,操作数栈:
70, 3, 2
- 取操作符
/
,优先级高于+
,压入操作符栈:#, +, cos, (, +, /
- 取操作数2,压入操作数栈:
70, 3, 2, 2
- 取操作符
/
,优先级等于/
,默认小于栈顶元素,弹出栈顶/
,弹出操作数栈中的2
与2
,执行计算2/2
,将结果1压入栈:70, 3, 1
。新操作符/
优先级大于+
,压入栈:#, +, cos, (, +, /
- 取操作数3压入:
70, 3, 1, 3
- 取操作符
^
,优先级高于/
,压入栈:#, +, cos, (, +, /, ^
- 取操作数2压入:
70, 3, 1, 3, 2
- 取操作符
-
,优先级小于^
,弹出^
与对应操作数,执行计算3^2
,将结果9压入栈:70, 3, 1, 9
- 操作符
-
优先级小于/
,弹出/
执行计算1/9
,将结果0.3333
压入栈:70, 3, 0.1111
- 操作符
-
与操作符+
同级,依照规则默认小于栈顶,弹出+
,执行计算3+0.1111
,压入结果:70, 3.1111
- 将操作符
-
压入栈:#, +, cos, (, -
- 获取操作数1:
70, 3.1111, 1
- 获取操作符
)
,默认小于除了左括号外所有运算符,弹出-
执行计算,结果:70, 2.1111
- 弹出操作符
(
- 获取操作符
*
,优先级小于cos
,弹出cos
执行运算:70, -0.514
,因为*
优先级大于+
,压入栈:#, +, *
- 取括号
(
,依据规则压入栈 - 取操作数4压入栈
- 取操作符
-
依据规则压入栈 - 取操作数3压入栈
- 取操作符
)
,依据规则弹出-
进行计算,得4-3=1
,压入栈:70, -0.514, 1
- 取得操作符
#
,按照顺序弹出所有操作符:-0.541 * 1 = -0.541
、70 + (-0.514) 69.486
- 计算结束
扩展:逆波兰式
链接:逆波兰式
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)