实验题目:算术表达式求值(算术计算器)
实验内容:
表达式求值是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子。一个算术表达式是由操作数(operand)、运算符(operator)和界限符 (delimiter)组成的。假设操作数是正整数,运算符只含加减乘除等四种二元运算符,界限符有左右括号和表达式起始、结束符“#”,如:#(7+15)*(23-28/4)#。引入表达式起始、结束符是为了方便。设计一个程序,演示算术表达式求值的过程。
实验要求:
1. 从文本文件输入任意一个语法正确的(中缀)表达式。
2. 利用栈结构,把(中缀)表达式转换成后缀表达式,并以适当的方式展示栈的状态变化过程和所得到的后缀表达式。
3. 利用栈结构,对后缀表达式进行求值,并以适当的方式展示栈的状态变化过程和最终结果。
目录
存储结构
typedef struct stack
{
int top;
ElemType elements[maxlength];
}STACK;
typedef struct stack_int
{
int top;
Elem elements[maxlength];
}STACK_Int;
/*将栈置为空*/
void MakeNull(STACK *s)
{
s->top=maxlength;
}
void MakeNull_Int(STACK_Int *s)
{
s->top=maxlength;
}
/*判断是否为空,为空返回1,否则返回0*/
int Empty(STACK s)
{
if(s.top<maxlength)
return 0;
else
return 1;
}
int Empty_Int(STACK_Int s)
{
if(s.top<maxlength)
return 0;
else
return 1;
}
/*返回栈顶元素,若stack为空则返回0*/
ElemType Top(STACK s)
{
if(Empty(s)==1)
{
return 0;
}
else
{
return s.elements[s.top];
}
}
Elem Top_Int(STACK_Int s)
{
if(Empty_Int(s)==1)
{
return 0;
}
else
{
return s.elements[s.top];
}
}
void Display(STACK s)
{
while(s.top!=maxlength)
{
printf("%c ",s.elements[s.top]);
s.top++;
}
}
void Display_Int(STACK_Int s)
{
while(s.top!=maxlength)
{
printf("%d ",s.elements[s.top]);
s.top++;
}
}
/*删除栈顶元素*/
void Pop(STACK *s)
{
if(Empty(*s) == 1)
{
printf("Stack is empty!");
}
else
{
s->top=s->top+1;
}
}
void Pop_Int(STACK_Int *s)
{
if(Empty_Int(*s) == 1)
{
printf("Stack is empty!");
}
else
{
s->top=s->top+1;
}
}
/*将元素x压入栈顶*/
void Push(STACK *s,ElemType x)
{
if(s->top==0)
{
printf("Stack is full!");
}
else
{
s->top=s->top-1;
s->elements[s->top]=x;
}
}
void Push_Int(STACK_Int *s,Elem x)
{
if(s->top==0)
{
printf("Stack is full!");
}
else
{
s->top=s->top-1;
s->elements[s->top]=x;
}
}
中缀表达式转后缀表达式
初始化一个栈,用于保存暂时还不能确定运算顺序的运算符,从左到右处理各个元素,直到末尾。可能遇到三种情况:
- 遇到操作数。直接加入后缀表达式。
- 遇到 '(' 直接入栈;遇到 ')' 则依次弹出栈内运算符并加入后缀表达式,直到遇到界限符 '(' 为止。注意:'(' 不加入后缀表达式。
- 遇到运算符,依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式,若碰到 '(' 或栈空则停止,之后再把当前运算符入栈。
按上述方法处理完所有字符后,将栈中剩余运算符依次弹出,并加入后缀表达式。
void Infix_to_Suffix(char suffix[20])
{
char ch,p;
STACK s;
int i=0,tag=1;
MakeNull(&s);
FILE *fp;
fp=fopen("Input.txt","r+");//打开文件
if(fp == NULL)
{
printf("Fail!");
exit(0);
}
ch=fgetc(fp);
while(ch != '#')//读到第一个界限符#处
{
ch=fgetc(fp);
}
while(ch != EOF)
{
ch=fgetc(fp);
if(ch >= '0'&&ch <= '9')//数字直接加入表达式中
{
suffix[i]=ch;
i++;
}
else if(ch == '(')//遇到左括号直接入栈
{
Push(&s,ch);
}
else if(ch == ')')//依次弹出栈内符号
{
p=Top(s);
while(p != '(')
{
suffix[i]=p;
i++;
Pop(&s);
p=Top(s);
}
Pop(&s);//弹出左括号
}
else if(ch=='+'||ch=='-')
{
if(Empty(s))//栈为空
{
Push(&s,ch);
}
else
{
p=Top(s);
while(Empty(s)==0 && p!='(')//栈为空或遇到左括号停止
{
suffix[i]=p;
i++;
Pop(&s);
p=Top(s);
}
Push(&s,ch);
}
}
else if(ch=='*'||ch=='/')
{
if(Empty(s))//栈为空
{
Push(&s,ch);
}
else if(Top(s)=='+'||Top(s)=='-')
{
Push(&s,ch);
}
else
{
p=Top(s);
while((p=='*'||p=='/')&&(p!='('))
{
suffix[i]=p;
i++;
Pop(&s);
p=Top(s);
}
}
}
printf("第%2d轮栈中元素 ",tag);//显示栈变化
tag++;
Display(s);
printf("\n");
}//全部读取完后栈中剩余元素出栈
while(!Empty(s))
{
suffix[i]=Top(s);
i++;
Pop(&s);
}
suffix[i]='#';
}
后缀表达式求值
用栈实现后缀表达式的计算,从左往右扫描下一个元素,直到处理完所有元素
- 若扫描到操作数则压入栈
- 若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶
void Calculation(char suffix[20])
{
int i=0,tag;
int value;
int temp1,temp2;
STACK s;
MakeNull(&s);//字符栈
STACK_Int a;
MakeNull_Int(&a);//数值栈
while(suffix[i] != '#')
{
if(suffix[i]>='0'&&suffix[i]<='9')
{
Push_Int(&a,suffix[i]-48);
}
else
{
temp1=Top_Int(a);
Pop_Int(&a);
temp2=Top_Int(a);
Pop_Int(&a);
if(suffix[i]=='+')
{
value=temp2+temp1;
}
else if(suffix[i]=='-')
{
value=temp2-temp1;
}
else if(suffix[i]=='*')
{
value=temp2*temp1;
}
else if(suffix[i]=='/')
{
value=temp2/temp1;
}
Push_Int(&a,value);
}
printf("第%2d轮栈中元素为:",tag);//记录栈的变化
Display_Int(a);
tag++;
printf("\n");
i++;
}
printf("结果为%d",Top_Int(a));
}
测试结果
Code::Blocks下读入文件和测试结果如下:
反思与总结
- 从文件读入时使用fgetc()函数,一次仅读入一个字符,未考虑数值为两位数及更多位数的情况
- 减法和除法时注意相减和相除的顺序
- 栈的实现时使用了分别定义了字符栈和整型栈,有些繁杂,需考虑是否可以适当简化
完整代码
#include <stdio.h>
#include <stdlib.h>
#define maxlength 30
#define ElemType char
#define Elem int
typedef struct stack
{
int top;
ElemType elements[maxlength];
}STACK;
typedef struct stack_int
{
int top;
Elem elements[maxlength];
}STACK_Int;
/*将栈置为空*/
void MakeNull(STACK *s)
{
s->top=maxlength;
}
void MakeNull_Int(STACK_Int *s)
{
s->top=maxlength;
}
/*判断是否为空,为空返回1,否则返回0*/
int Empty(STACK s)
{
if(s.top<maxlength)
return 0;
else
return 1;
}
int Empty_Int(STACK_Int s)
{
if(s.top<maxlength)
return 0;
else
return 1;
}
/*返回栈顶元素,若stack为空则返回0*/
ElemType Top(STACK s)
{
if(Empty(s)==1)
{
return 0;
}
else
{
return s.elements[s.top];
}
}
Elem Top_Int(STACK_Int s)
{
if(Empty_Int(s)==1)
{
return 0;
}
else
{
return s.elements[s.top];
}
}
void Display(STACK s)
{
while(s.top!=maxlength)
{
printf("%c ",s.elements[s.top]);
s.top++;
}
}
void Display_Int(STACK_Int s)
{
while(s.top!=maxlength)
{
printf("%d ",s.elements[s.top]);
s.top++;
}
}
/*删除栈顶元素*/
void Pop(STACK *s)
{
if(Empty(*s) == 1)
{
printf("Stack is empty!");
}
else
{
s->top=s->top+1;
}
}
void Pop_Int(STACK_Int *s)
{
if(Empty_Int(*s) == 1)
{
printf("Stack is empty!");
}
else
{
s->top=s->top+1;
}
}
/*将元素x压入栈顶*/
void Push(STACK *s,ElemType x)
{
if(s->top==0)
{
printf("Stack is full!");
}
else
{
s->top=s->top-1;
s->elements[s->top]=x;
}
}
void Push_Int(STACK_Int *s,Elem x)
{
if(s->top==0)
{
printf("Stack is full!");
}
else
{
s->top=s->top-1;
s->elements[s->top]=x;
}
}
void Infix_to_Suffix(char suffix[20])
{
char ch,p;
STACK s;
int i=0,tag=1;
MakeNull(&s);
FILE *fp;
fp=fopen("Input.txt","r+");//打开文件
if(fp == NULL)
{
printf("Fail!");
exit(0);
}
ch=fgetc(fp);
while(ch != '#')//读到第一个界限符#处
{
ch=fgetc(fp);
}
while(ch != EOF)
{
ch=fgetc(fp);
if(ch >= '0'&&ch <= '9')//数字直接加入表达式中
{
suffix[i]=ch;
i++;
}
else if(ch == '(')//遇到左括号直接入栈
{
Push(&s,ch);
}
else if(ch == ')')//依次弹出栈内符号
{
p=Top(s);
while(p != '(')
{
suffix[i]=p;
i++;
Pop(&s);
p=Top(s);
}
Pop(&s);//弹出左括号
}
else if(ch=='+'||ch=='-')
{
if(Empty(s))//栈为空
{
Push(&s,ch);
}
else
{
p=Top(s);
while(Empty(s)==0 && p!='(')//栈为空或遇到左括号停止
{
suffix[i]=p;
i++;
Pop(&s);
p=Top(s);
}
Push(&s,ch);
}
}
else if(ch=='*'||ch=='/')
{
if(Empty(s))//栈为空
{
Push(&s,ch);
}
else if(Top(s)=='+'||Top(s)=='-')
{
Push(&s,ch);
}
else
{
p=Top(s);
while((p=='*'||p=='/')&&(p!='('))
{
suffix[i]=p;
i++;
Pop(&s);
p=Top(s);
}
}
}
printf("第%2d轮栈中元素 ",tag);//显示栈变化
tag++;
Display(s);
printf("\n");
}//全部读取完后栈中剩余元素出栈
while(!Empty(s))
{
suffix[i]=Top(s);
i++;
Pop(&s);
}
suffix[i]='#';
}
void Calculation(char suffix[20])
{
int i=0,tag;
int value;
int temp1,temp2;
STACK s;
MakeNull(&s);//字符栈
STACK_Int a;
MakeNull_Int(&a);//数值栈
while(suffix[i] != '#')
{
if(suffix[i]>='0'&&suffix[i]<='9')
{
Push_Int(&a,suffix[i]-48);
}
else
{
temp1=Top_Int(a);
Pop_Int(&a);
temp2=Top_Int(a);
Pop_Int(&a);
if(suffix[i]=='+')
{
value=temp2+temp1;
}
else if(suffix[i]=='-')
{
value=temp2-temp1;
}
else if(suffix[i]=='*')
{
value=temp2*temp1;
}
else if(suffix[i]=='/')
{
value=temp2/temp1;
}
Push_Int(&a,value);
}
printf("第%2d轮栈中元素为:",tag);//记录栈的变化
Display_Int(a);
tag++;
printf("\n");
i++;
}
printf("结果为%d",Top_Int(a));
}
int main()
{
char suffix[20];
Infix_to_Suffix(suffix);
int i=0;
while(suffix[i]!='#')
{
printf("%c ",suffix[i]);
i++;
}
printf("\n");
Calculation(suffix);
return 0;
}