首先我们实现一个计算器,用户所输入的为中缀表达式,这是通用的算术公式的表达方法,但是有一个缺点就是不容易被计算机所理解。所以,有了所谓的后缀表达式!
后缀表达式:不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:(2 + 1) * 3 , 即2 1 + 3 *
然后咱们通过栈来实现这个计算器的功能。
在这里中缀表达式转后缀表达式我主要采用了两个数组和一个栈实现,这个栈首先是来保存运算符,通过数组和栈配合实现后缀表达式,然后为了得到结果,使用了strtok()函数,这个函数用来字符串分割,最终可以得到结果。
详细代码如下:
cal.h
#define _CRT_SECURE_NO_WARNINGS 1
#ifndef __CAL_H__
#define __CAL_H__
//利用顺序栈实现计算器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 50
typedef int SElemType;
//定义一个顺序存储栈
typedef struct
{
SElemType data[MAXSIZE];
int top;
}SqStack;
int To_PostFix(char *infix, char *postfix);
int Calculator(char *postfix, int *result);
#endif // !__CAL_H__
cal.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"cal.h"
/*******************栈的基本操作********************************/
int init_stack(SqStack *s)
{
s->top = -1;
return 1;
}
int clear_stack(SqStack *s)
{
s->top = -1;
return 1;
}
int stack_empty(SqStack s)
{
if (s.top == -1)
return 1;
else
return 0;
}
int stack_length(SqStack *s)
{
return s->top + 1;
}
int push(SqStack *s, SElemType e)
{
if (s->top == MAXSIZE - 1)
return 0;
s->top++;
s->data[s->top] = e;
return 1;
}
int pop(SqStack *s, SElemType *e)
{
if (s->top == -1)
return 0;
*e = s->data[s->top];
s->top--;
return 1;
}
/*******************中序表达式转换为后续表达式********************************/
int To_PostFix(char *infix, char *postfix)
{
SqStack s;
int e = 0;
int i = 0, j = 0;
int flag = 0;
if (init_stack(&s) != 1) //判断栈是否为空,
return 0;
while (infix[i] != '\0') //说明栈中有元素。
{
while (infix[i] >= '0' && infix[i] <= '9') //如果是数字则输出
{
if (flag) //考虑负数的情况
{
flag = 0;
postfix[j++] = '-';
}
postfix[j++] = infix[i];//让存放后缀表达式的数组存放字符
i++;
if (infix[i]<'0' || infix[i]>'9') //判断是否为操作符,如果是,让后缀表达式中存放一个' '
postfix[j++] = ' ';
}
if (infix[i] == ')' ) //如果是关于括号的符号,则进行栈操作
{
pop(&s, &e);
while (e != '(' )
{
postfix[j++] = e;
postfix[j++] = ' ';
pop(&s, &e);
}
}
else if (infix[i] == '+' || infix[i] == '-') //对于同运算级的+和-操作
{
if (infix[i] == '-' && (i == 0 || (i != 0 && (infix[i - 1]<'0' || infix[i - 1]>'9')))) //当'-'号处于第一位,或前面是符号时,为负号标志
flag = 1;
else if (stack_empty(s))
push(&s, infix[i]);
else
{
do
{
pop(&s, &e);
if (e == '(' )
push(&s, e);
else
{
postfix[j++] = e;
postfix[j++] = ' ';
}
} while (!stack_empty(s) && e != '(' );
push(&s, infix[i]);
}
}
else if (infix[i] == '*' || infix[i] == '/' || infix[i] == '(' )//对于乘除以及括号的开始进行压栈
push(&s, infix[i]);
else if (infix[i] == '\0')
break;
else
return 0;
i++;
}
while (!stack_empty(s))
{
pop(&s, &e);
postfix[j++] = e;
postfix[j++] = ' ';
}
clear_stack(&s);
return 1;
}
/*******************根据后续表达式计算结果********************************/
int Calculator(char *postfix, int *result)
{
SqStack s;
char *op; //存放后缀表达式中的每个因数或运算符
char *buf = postfix; //声明bufhe saveptr两个变量,是strtok_r函数的需要。
char *saveptr = NULL;
int d, e, f;
if (init_stack(&s) != 1)
return 0;
while ((op = strtok(buf, " ")) != NULL)//利用字符串分割函数
{
buf = NULL; //把指针置空
switch (op[0])
{
case '+':
pop(&s, &d);
pop(&s, &e);
f = d + e;
push(&s, f);
break;
case '-':
if (op[1] >= '0' && op[1] <= '9') //是负号而不是减号
{
d = atoi(op);
push(&s, d);
break;
}
pop(&s, &d);
pop(&s, &e);
f = e - d;
push(&s, f);
break;
case '*':
pop(&s, &d);
pop(&s, &e);
f = e*d;
push(&s, f);
break;
case '/':
pop(&s, &d);
pop(&s, &e);
f = e / d;
push(&s, f);
break;
default: //考虑数字的情况,进行atoi函数进行转化
d = atoi(op);
push(&s, d); //进行压栈
break;
}
}
pop(&s, result);
clear_stack(&s);
return 0;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"cal.h"
void Test()
{
char infix[MAXSIZE] = { 0 };
char postfix[MAXSIZE] = { 0 };
int result = 0;
printf("请输入一个中缀表达式:\n");
scanf("%s", infix);
fflush(stdin);
To_PostFix(infix, postfix);
printf("转换得到的后缀表达式是:\n");
printf("%s\n", postfix);
Calculator(postfix, &result);
printf("最后得到的结果:\n");
printf("%d\n", result);
}
int main()
{
Test();
system("pause");
return 0;
}