1 问题描述
表达式求值是比较常见的问题,通常在编写程序时,直接写出表达式让编译器去处理,却很少关心编译器是如何对表达式求值。
整数加减乘除四则运算的规则如下:
1)先乘除,后加减;
2)同一优先级,从左算到右;
3) 先括号内,后括号外。
按中缀形式输入一个四则运算的表达式,利用算符优先关系把其转换为后缀表达式输出,并求表达式的值。假设输入的表达式中的操作数都是1位整数。
一个简单合法的中缀表达式可由“(”,“)”,“0”~“9”,“+”,“-”,“*”,“/”(“/”表示整数除法)构成。
- 输入要求
输入数据可以有多组,每一组测试数据为带小括号的四则运算中缀表达式。
- 输出要求
对于每组测试数据输出两行,第一行四则运算表达式的后缀表达式(每个数字或者操作符之间输出空格,最后一个元素后没有空格),第二行运算结果。 除法操作为整除,比如6/4=1。
程序如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define FALSE 0
#define TRUE 1
#define STACKSIZE 20 //堆栈容量,可根据需要进行调整
#define ITEMSIZE 20 //表达式中元素的最大长度,可根据需要进行调整
#define EXPSIZE 200 //表达式最大长度
typedef char ElemType;
typedef int BOOL;
/*用于前缀转后缀表达式的栈空间(操作符入栈)*/
typedef struct stack
{
int top;
int maxSize;
ElemType *element;
}Stack;
/*用于后缀表达式计算的栈空间(操作数入栈)*/
typedef struct stack_
{
int top;
int maxSize;
double *element;
}Stack_;
void Create(Stack *S,int mSize)
{
S->maxSize = mSize;
S->element = (ElemType*)malloc(sizeof(ElemType)*mSize);
S->top = -1;
}
void Create_(Stack_ *S, int mSize)
{
S->maxSize = mSize;
S->element = (double*)malloc(sizeof(double)*mSize);
S->top = -1;
}
BOOL IsFull(Stack *S)
{
return S->top == S->maxSize - 1;
}
BOOL IsFull_(Stack_ *S)
{
return S->top == S->maxSize - 1;
}
BOOL Push(Stack *S, ElemType x)
{
if (IsFull(S))
return FALSE;
S->top++;
S->element[S->top] = x;
return TRUE;
}
BOOL Push_(Stack_ *S, double x)
{
if (IsFull(S))
return FALSE;
S->top++;
S->element[S->top] = x;
return TRUE;
}
BOOL IsEmpty(Stack *S)
{
return S->top == -1;
}
BOOL IsEmpty_(Stack_ *S)
{
return S->top == -1;
}
BOOL Top(Stack *S, ElemType *x)
{
if (IsEmpty(S)) return FALSE;
*x = S->element[S->top];
return TRUE;
}
BOOL Top_(Stack_ *S, double *x)
{
if (IsEmpty(S)) return FALSE;
*x = S->element[S->top];
return TRUE;
}
BOOL Pop(Stack *S)
{
if (IsEmpty(S)) return FALSE;
S->top--;
return TRUE;
}
BOOL Pop_(Stack_ *S)
{
if (IsEmpty_(S)) return FALSE;
S->top--;
return TRUE;
}
void Output(Stack *S)
{
int i ;
printf("当前栈空间:");
for (i = 0; i <= S->top; i++)
{
printf("%c ", S->element[i]);
}
printf("\n");
}
void Destroy(Stack *S)
{
S->maxSize = 0;
free(S->element);
S->top = -1;
}
void Destroy_(Stack_ *S)
{
S->maxSize = 0;
free(S->element);
S->top = -1;
}
BOOL IsLegal(char *postfix)
{
int i;
char c;
for (i = 0; i < strlen(postfix); i++)
{
c = postfix[i];
if (!((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '*' || c == '/' || c == ' ' || c == '(' || c == ')'))
return FALSE;
}
return TRUE;
}
/*提取元素,返回元素的类型*/
int GetItem(char *postfix, int *curPos, char *item)
{
int i = 0, k = *curPos, flag;
if (postfix[k] == '.')
flag = -1;
else if (postfix[k] >= '0'&& postfix[k] <= '9')
{
while ((postfix[k] >= '0'&&postfix[k] <= '9') || postfix[k] == '.')
item[i++] = postfix[k++];
item[i] = '\0';
flag = 0;
}
else
{
item[0] = postfix[k++];
item[1] = '\0';
flag = 1;
}
/*跳过当前元素的空格,下一次取元素起始位置是非空字符*/
while (postfix[k] == ' ')
k++;
*curPos = k;
return flag;
}
/*获取栈外优先级*/
int ICP(char c)
{
if (c == '#')
return 0;
else if (c == '(')
return 7;
else if (c == '*' || c == '/')
return 4;
else if (c == '+' || c == '-')
return 2;
else if (c == ')')
return 1;
else
{
printf("后缀表达式不支持此操作符%c!\n", c);
exit(0);
}
}
/*获取栈内优先级*/
int ISP(char c)
{
if (c == '#')
return 0;
else if (c == '(')
return 1;
else if (c == '*' || c == '/')
return 5;
else if (c == '+' || c == '-')
return 3;
else if (c == ')')
return 7;
else
{
printf("后缀表达式不支持此操作符%c!\n", c);
exit(0);
}
}
/*前缀转后缀表达式*/
void InfixToPostfix(char *infix, char *postfix)
{
Stack S;
char item[ITEMSIZE];//存储表达式中的各个元素
int flag = -1, //代表操作符类型
curPos = 0,
k = 0, i;
char ch, //存放操作符元素
curOP; //存储中缀表达式存储在数组中的操作符元素
while (infix[curPos] == ' ')
curPos++; //过滤空格
Create(&S, STACKSIZE);
Push(&S, '#');
while (curPos < strlen(infix))
{
flag = GetItem(infix, &curPos, item);//获取元素即元素类型(返回值为1代表运算符,返回值0代表操作数,-1代表异常)
//printf("item:%s\t",item);
/*flag==-1,此时异常*/
if (flag == -1)
{
printf("异常:中缀表达式不合法!\n");
exit(0);
}
/*flag==1,此时为运算符*/
else if (flag == 1)
{
curOP = item[0];
if (curOP == ')')
{
Top(&S, &ch);
Pop(&S);
//Output(&S);
//遇到右括号则连续出栈直至遇到左括号
while (ch!='(')
{
postfix[k++] = ch;
postfix[k++] = ' ';
Top(&S, &ch);
Pop(&S);
//Output(&S);
postfix[k] = '\0';
//printf("进行括号内的运算符处理时,当前后缀表达式为%s \n", postfix);
}
//Pop(&S);
}
else if (curOP == '(')
{
Push(&S, curOP);
//Output(&S);
//postfix[k] = '\0';
//printf("进行括号内的运算符处理时,当前后缀表达式为%s \n", postfix);
}
else
{
//ch存放的是栈顶元素,curOP存放的是栈外当前操作符
Top(&S, &ch);
//如果栈外优先级 >= 栈内优先级
if (ICP(curOP) >= ISP(ch))
{
Push(&S, curOP);
//Output(&S);
}
else
{
//如果栈内优先级 > 栈外优先级,连续出栈直到栈内 > 栈外
while (ICP(curOP) < ISP(ch))
{
postfix[k++] = ch;
postfix[k++] = ' ';
Pop(&S);
Top(&S, &ch);
//Output(&S);
}
Push(&S, curOP);
}
}
//postfix[k] = '\0';
//printf("此时的后缀表达式为%s \n", postfix);
}
/*flag==0,此时为操作数*/
else
{
for (i = 0; i < strlen(item); i++, k++)
{
postfix[k] = item[i];
postfix[++k] = ' ';
}
//postfix[k] = '\0';
//printf("此时的后缀表达式为%s \n", postfix);
}
}
Top(&S, &ch);
Pop(&S);
while (ch != '#')
{
postfix[k++] = ch;
postfix[k++] = ' ';
Top(&S, &ch);
Pop(&S);
postfix[k] = '\0';
//printf("遍历完毕,栈非空情况下,此时的后缀表达式为%s \n", postfix);
//Output(&S);
}
postfix[--k] = '\0';
}
/*提取栈空间的两个值让并将计算结果入栈*/
void DoOperator(Stack_ *S, char oper)
{
double oper1, oper2;
if (!Top_(S, &oper1))
{
printf("异常:后缀表达式格式出错,存在多余的操作符!\n");
exit(0);
}
Pop_(S);
if (!Top_(S, &oper2))
{
printf("异常:后缀表达式格式出错,存在多余的操作符!\n");
exit(0);
}
Pop_(S);
//printf("当前运算:%.2f%c%.2f\n", oper1, oper, oper2);
switch (oper)
{
case '+':
Push_(S, oper1 + oper2);
break;
case '-':
Push_(S, oper2 - oper1);
break;
case '*':
Push_(S, oper2 * oper1);
break;
case '/':
if (fabs(oper1) < 1e-6)
{
printf("异常:除数不可为0!\n");
exit(0);
}
else Push_(S, oper2/ oper1);
break;
case '^':
Push_(S, pow(oper2 , oper1));
break;
}
}
double Caculating(char *postfix)
{
Stack_ S;
char item[ITEMSIZE];
double data;
int flag = -1;
int curPos = 0;
while (postfix[curPos] == ' ')
curPos++;
Create_(&S, STACKSIZE);
while (curPos < strlen(postfix))
{
flag = GetItem(postfix, &curPos, item);
if (flag == -1)
{
printf("异常:后缀表达式不合法!\n");
exit(0);
}
else if (flag == 1)
{
//printf("当前运算符%c\n", item[0]);
switch (item[0])
{
case '+':
case '-':
case '*':
case '/':
case '^':
DoOperator(&S, item[0]);
break;
}
}
else
{
data = atof(item);
//printf("当前数据为%f\n", data);
Push_(&S, data);
}
}
if (S.top == 0)
Top_(&S, &data);
else
{
printf("异常:后缀表达式格式出错,存在多余操作数!\n");
exit(0);
}
Destroy_(&S);
return data;
}
int main()
{
/*
可直接复制的测试案例:
(7+8)*9 7 8 + 9 * 135
8-(3+2*6)/5+4 8 3 2 6 * + 5 / - 4 + 9
*/
char infix[EXPSIZE];
char postfix[EXPSIZE];
printf("请输入中缀表达式:\n");
gets(infix);
if (!IsLegal(infix))
{
printf("异常:中缀表达书存在非法字符!\n");
return 0;
}
InfixToPostfix(infix, postfix);
printf("\n对应后缀表达式为%s \n", postfix);
printf("结果为%.2f\n", Caculating(postfix));
return 0;
}
运行结果如下