数据结构用栈实现复杂计算器,当时真的写的我快狗带了,终于在csdn里的小角落的评论里找到大佬的代码,真的肥肠厉害!
计算器真的好难,需要考虑的东西有很多,多位数字判断该如何办呢,要求实现开方的话,小数要如何处理呢,要实现abs的话,负数也需要考虑。括号带括号的判断该怎么具体实现。以及错误的提示,输入了两个减号该怎么报错,等等等等。在细节各方面非常复杂,让人头疼。
我发现的大佬的代码不仅考虑了函数,还发现了双目运算符,负数,括号,空格,不止整形还有浮点数,真的令人敬佩。运算符是用了左结合性和右结合性,真的当时都没想到(捂脸),接着是优先级判断,将输入的东西分为三种,数字,函数,运算符。
最后代码可优化的地方应该就是一些报警,没有直接显示,而是转化了一下,空格就直接无视然后能算出正确的,除0还有开方0,自己加一下就行,这个倒没什么。以及对输入了错误的运算符没有办法,比如9-+8就不行,还是会运算,看看有没有其他大佬能解决。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define ElemItem Item
#define SUCCEED 1
#define ERROR 0
#define MAXLENGTH 20
struct Item{
int type; //0表示单目运算符,1表示双目运算符,2表示数字
double num; //如果是数字就保存在这里
char oper[MAXLENGTH]; //如果是运算符就保存在这里
}nullItem;
typedef struct SNode{
ElemItem data;
SNode *next;
}*Stack;
struct QNode{
ElemItem data;
QNode *next;
};
struct Queue{
QNode *front;
QNode *rear;
};
void initStack(Stack *s){
*s = NULL;
}
void push(Stack *s, ElemItem e){
SNode *p = (SNode*)malloc(sizeof(SNode));
p->data = e;
p->next = *s;
*s = p;
}
int pop(Stack *s, ElemItem *e = NULL){
if(*s == NULL){
return ERROR;
}
if(e != NULL){
*e = (*s)->data;
}
SNode *p = *s;
*s = (*s)->next;
free(p);
return SUCCEED;
}
ElemItem getSData(Stack s){
if(s == NULL){
return nullItem;
}
return s->data;
}
void initQueue(Queue *q){
q->front = NULL;
q->rear = NULL;
}
void in(Queue *q, ElemItem e){
QNode* p = (QNode*)malloc(sizeof(QNode));
p->data = e;
p->next = NULL;
if(q->rear != NULL){
q->rear->next = p;
}
q->rear = p;
if(q->front == NULL){
q->front = p;
}
}
int out(Queue *q, ElemItem *e){
if(q->front == NULL){
return ERROR;
}
*e = q->front->data;
QNode *p = q->front;
q->front = q->front->next;
free(p);
return SUCCEED;
}
ElemItem getQData(Queue q){
if(q.front == NULL){
return nullItem;
}
return q.front->data;
}
int getPriority(char *a){ //判断优先级,将它们分为四种情况
if(strcmp(a, "+") == 0 || strcmp(a, "-") == 0)
return 1;
if(strcmp(a, "*") == 0 || strcmp(a, "/") == 0)
return 2;
if(strcmp(a, "^") == 0)
return 3;
if(strcmp(a, "sqrt") == 0 || strcmp(a, "cos") == 0 || strcmp(a, "tan") == 0 \
|| strcmp(a, "ln") == 0 || strcmp(a, "abs") == 0 \
|| strcmp(a, "arcsin") == 0 || strcmp(a, "arccos") == 0 || strcmp(a, "arctan") == 0)
return 4; //xiugaileeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
return -1;
}
int getCombination(char *a){ //1表示左结合,0表示右结合
if(strcmp(a, "+") == 0 || strcmp(a, "-") == 0 || strcmp(a, "*") == 0 || strcmp(a, "/") == 0 || strcmp(a, "^") == 0)
return 1;
if(strcmp(a, "sqrt") == 0 || strcmp(a, "cos") == 0 || strcmp(a, "tan") == 0 \
|| strcmp(a, "ln") == 0 || strcmp(a, "abs") == 0 \
|| strcmp(a, "arcsin") == 0 || strcmp(a, "arccos") == 0 || strcmp(a, "arctan") == 0)
return 0;
return -1;
}
int getOrder(char *a){ //0表示单目,1表示双目
if(strcmp(a, "+") == 0 || strcmp(a, "-") == 0 || strcmp(a, "*") == 0 || strcmp(a, "/") == 0 || strcmp(a, "^") == 0)
return 1;
if(strcmp(a, "sqrt") == 0 || strcmp(a, "cos") == 0 || strcmp(a, "tan") == 0 \
|| strcmp(a, "ln") == 0 || strcmp(a, "abs") == 0 \
|| strcmp(a, "arcsin") == 0 || strcmp(a, "arccos") == 0 || strcmp(a, "arctan") == 0)
return 0;
return -1;
}
double getResult0(char *oper, double a1){ //对单个数字的运算
if(strcmp(oper, "+") == 0)
return a1;
if(strcmp(oper, "-") == 0)
return -a1;
if(strcmp(oper, "sqrt") == 0)
return sqrt(a1);
if(strcmp(oper, "cos") == 0)
return cos(a1);
if(strcmp(oper, "tan") == 0)
return tan(a1);
if(strcmp(oper, "ln") == 0)
return log(a1);
if(strcmp(oper, "abs") == 0)
return abs(a1);
if(strcmp(oper, "arcsin") == 0)
return asin(a1);
if(strcmp(oper, "arccos") == 0)
return acos(a1);
if(strcmp(oper, "arctan") == 0)
return atan(a1);
return 0;
}
double getResult1(char *oper, double a1, double a2){ //对多个数字的运算
if(strcmp(oper, "+") == 0)
return a1+a2;
if(strcmp(oper, "-") == 0)
return a1-a2;
if(strcmp(oper, "*") == 0)
return a1*a2;
if(strcmp(oper, "/") == 0)
return a1/a2;
if(strcmp(oper, "^") == 0)
return pow(a1,a2);
return 0;
}
double calculate(char *expression){
//对表达式信息初步读取
int length = strlen(expression);
Queue firstExp;
initQueue(&firstExp);
int flag = -1; //0表示数字,1表示运算符,2表示函数
char tmp[MAXLENGTH] = {'\0'};
for(int i=0; i<length; i++){
if(expression[i] != ' '){
if((expression[i] >= '0' && expression[i] <= '9') || expression[i] == '.'){
if(flag == 1 || flag == 2){ //当读取的内容不属于数字时
Item item;
item.type = getOrder(tmp);
strcpy(item.oper, tmp);
in(&firstExp, item);
flag = 0;
tmp[0] = '\0';
}
if(flag == -1){
flag = 0;
}
}else{
if(expression[i] >= 'a' && expression[i] <= 'z'){
if(flag == 0){ //判断内容属于函数
Item item;
item.type = 2;
item.num = strtod(tmp, NULL);
in(&firstExp, item);
flag = 2;
tmp[0] = '\0';
}else if(flag == 1){
Item item;
item.type = getOrder(tmp);
strcpy(item.oper, tmp);
in(&firstExp, item);
flag = 2;
tmp[0] = '\0';
}else if(flag == 2 && getOrder(tmp) != -1){
Item item;
item.type = getOrder(tmp);
strcpy(item.oper, tmp);
in(&firstExp, item);
tmp[0] = '\0';
}
if(flag == -1){
flag = 2;
}
}else{
if(flag == 0){ //判断内容属于运算符
Item item;
item.type = 2;
item.num = strtod(tmp, NULL);
in(&firstExp, item);
flag = 1;
tmp[0] = '\0';
}else if(flag == 2){
Item item;
item.type = getOrder(tmp);
strcpy(item.oper, tmp);
in(&firstExp, item);
flag = 1;
tmp[0] = '\0';
}else if(flag == 1){
Item item;
item.type = getOrder(tmp);
strcpy(item.oper, tmp);
in(&firstExp, item);
tmp[0] = '\0';
}
if(flag == -1){
flag = 1;
}
}
}
int l = strlen(tmp);
if(l < MAXLENGTH-1){
tmp[l] = expression[i];
tmp[l+1] = '\0';
}
//printf("first runing\n");
}
}
if(flag == 0){
Item item;
item.type = 2;
item.num = strtod(tmp, NULL);
in(&firstExp, item);
}else{
Item item;
item.type = 1;
strcpy(item.oper, tmp);
in(&firstExp, item);
}
tmp[0] = '\0';
//printf("first end\n");
/*Item i;
while(out(&firstExp, &i)){
if(i.type == 2){
printf("%lf\n", i.num);
}else{
printf("%s\n", i.oper);
}
}*/
//生成后缀表达式
int frontHasNum = 0; //最开始有无数字,0表示无数字,1表示有数字,如果最开始无数字,则第一个运算符降为单目运算符
Stack operStack;
initStack(&operStack);
Queue secondExp;
initQueue(&secondExp);
Item firstItem;
while(out(&firstExp, &firstItem)){
if(firstItem.type == 2){
frontHasNum = 1;
in(&secondExp, firstItem);
}else{
if(strcmp(firstItem.oper, "(") == 0){
frontHasNum = 0;
push(&operStack, firstItem);
}else if(strcmp(firstItem.oper, ")") == 0){
frontHasNum = 1;
Item t;
while(strcmp(getSData(operStack).oper, "(") != 0){
if(!pop(&operStack, &t))
break;
in(&secondExp, t);
//printf("second 1 while\n");
}
pop(&operStack);
}else{
Item t;
while((getPriority(firstItem.oper) < getPriority(getSData(operStack).oper)) \
|| (getPriority(firstItem.oper)==getPriority(getSData(operStack).oper) && getCombination(getSData(operStack).oper)==1)){
if(!pop(&operStack, &t))
break;
in(&secondExp, t);
//printf("second 2 while\n");
}
if(frontHasNum == 0){
frontHasNum = 1;
firstItem.type = 0;
}
push(&operStack, firstItem);
}
}
//printf("second runing\n");
}
while(pop(&operStack, &firstItem)){
in(&secondExp, firstItem);
//printf("second in runing\n");
}
//printf("second end\n");
/*Item i2;
while(out(&secondExp, &i2)){
if(i2.type == 2){
printf("%lf\n", i2.num);
}else{
printf("%s\n", i2.oper);
}
}*/
//计算
Stack startCalculate;
initStack(&startCalculate);
Item startItem;
while(out(&secondExp, &startItem)){
if(startItem.type == 2){
push(&startCalculate, startItem);
}else{
if(startItem.type == 0){
Item a;
pop(&startCalculate, &a);
a.num = getResult0(startItem.oper, a.num);
push(&startCalculate, a);
}else if(startItem.type == 1){
Item a1,a2;
pop(&startCalculate, &a2);
pop(&startCalculate, &a1);
Item a;
a.type = 2;
a.num = getResult1(startItem.oper, a1.num, a2.num);
push(&startCalculate, a);
}
}
//printf("calculating\n");
}
Item result;
pop(&startCalculate, &result);
return result.num;
}
int main(int argc, char *argv[]){
char exp[200] = {'\0'};
if(argc != 2){
printf("输入表达式:\n");
//scanf("%s", exp);
gets(exp);
}else{
strcpy(exp, argv[1]);
}
printf("计算结果为:%lf\n", calculate(exp));
return 0;
}