要求:
输入在一行中给出不含空格的中缀表达式,可包含+、-、*、/以及左右括号
即二元运算符位于两个运算数中间
解决思路:
使用堆栈保存运算符
1.若遇到操作符,则直接输出
2.若是左括号,则将其压入堆栈中
3.若遇到的是右括号,表明括号内的中缀表达式已经扫描完毕,将栈顶的运算符出栈并输出,直到遇到左括号(左括号出栈,但不输出)
4. 若遇到的是运算符,若该运算符的优先级大于栈顶运算符的优先级,则把它压栈
若该运算符的优先级小于等于栈顶运算符的优先级,将栈顶运算符出栈并输出,再比较新的栈顶运算符,按照同样的处理方法,直到该运算符的优先级大于栈顶运算符的优先级为止,然后将该运算符压栈
5.若中缀表达式中的各对象处理完毕,则把堆栈中存留的运算符一并输出
代码:
//中缀表达式转换成后缀表达式
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include<ctype.h>
#define MAXL 21
/*------堆栈定义-------*/
typedef char ElementType;
typedef int Position;
typedef struct SNode *PtrToSNode;
struct SNode{
ElementType *Data;
Position Top;
int MaxSize;
};
typedef PtrToSNode Stack;
Stack CreateStack(int MaxSize);
bool IsEmpty(Stack S);
void Push(Stack S,ElementType X);
ElementType Peek(Stack S);//访问栈顶元素,但不出栈
ElementType Pop(Stack S);
/*------堆栈定义结束-------*/
//运算符的优先级类型
typedef enum{
//左括号,右括号,加,减,乘,除 ,结束符, 数字
lpr,rpr,plus,minus,times,divide,eos,operand
}Precedence;
bool IsSign(char *expr,int i);//判断'+''-'是运算符还是数字前的加减号
char GetOp(char *expr,int *i,char *Postfix,int *j);//获取运算符
Precedence GetToken(char op);//获取运算符
void ToPostfix(char *expr);//后缀表达式核心函数
int main()
{
char Str[MAXL];
printf("请输入中缀表达式:");
scanf("%s",Str);
printf("输出的后缀表达式为:");
ToPostfix(Str);
return 0;
}
/*------表达式转换核心函数-------*/
void ToPostfix(char *expr)
{
int i,j,L;
char Postfix[2*MAXL],Op;
Stack S;
Precedence token;
S=CreateStack(MAXL);
L=strlen(expr);
j=0;//j指向 Postfix[]中当前要写入的位置
for(i=0;i<L;i++){
Op=GetOp(expr,&i,Postfix,&j);
token=GetToken(Op);
if(token==operand)continue;//数字不处理
switch(token){//处理运算符
case lpr:Push(S,'(');break;//左括号入栈
case rpr://右括号
/*括号内的中缀表达式扫描完毕,把左括号前的所有运算符写入Postfix[]*/
while(Peek(S)!='('){//访问栈顶元素
Postfix[j++]=Pop(S);//出栈
Postfix[j++]=' '; //写入空格
}
Pop(S);//删除左括号
break;
default://其他运算符
//当前运算符优先级小于等于栈顶运算符优先级,直接出栈并输出
while(!IsEmpty(S) && Peek(S)!='(' && token<=GetToken(Peek(S))){
Postfix[j++]=Pop(S);
Postfix[j++]=' ';
}
Push(S,Op);//当前运算符优先级大于栈顶运算符优先级 ,压栈
break;
}
}
//中缀表达式中的各对象处理完毕,把堆栈中存留的运算符一并输出
while(!IsEmpty(S)){
Postfix[j++]=Pop(S);
Postfix[j++]=' ';
}
Postfix[j-1]='\0';
printf("%s\n",Postfix);
}
/*------表达式转换核心函数结束-------*/
/*------堆栈操作-------*/
Stack CreateStack(int MaxSize)
{
Stack S=(Stack)malloc(sizeof(struct SNode));
S->Data =(ElementType *)malloc(sizeof(ElementType)*MaxSize);
S->MaxSize =MaxSize;
S->Top =-1;
return S;
}
bool IsEmpty(Stack S)
{
return (S->Top ==-1);
}
void Push(Stack S,ElementType X)
{
//简版入栈,不考虑栈满
S->Data [++(S->Top) ]=X; //注意先加Top
}
ElementType Peek(Stack S)
{
return (S->Data [S->Top ]);
}
ElementType Pop(Stack S)
{
//简版出栈,不考虑栈空
return (S->Data [(S->Top )--]);
}
/*------堆栈操作结束-------*/
/*------辅助函数-------*/
bool IsSign(char *expr,int i)
{
//如果前一个字符不是数字且不是右括号,那么这个字符是正负号
//如果它是表达式的第一个字符,也是正负号
if(!i || (!isdigit(expr[i-1]) && (expr[i-1]!=')'))) //是正负号
return true;
else return false;//是运算符
}
char GetOp(char *expr,int *i,char *Postfix,int *j)
{
//如果是数字则直接写入Postfix[]并返回‘0’
//如果是运算符则返回字符
if(isdigit(expr[(*i)])){
//读入一个纯数字
while(isdigit(expr[(*i)]) || (expr[(*i)]=='.'))
Postfix[(*j)++]=expr[(*i)++];
Postfix[(*j)++]=' ';
(*i)--;
return '0';
}
//不是纯数字——运算符或正负号,括号
switch(expr[(*i)]){
case'+':
if(IsSign(expr,(*i))){//正号
(*i)++;
return GetOp(expr,i,Postfix,j);//继续扫描
}
else return '+';//运算符
case'-':
if(IsSign(expr,(*i))){//负号
Postfix[(*j)++]='-';//放入后缀表达式
(*i)++;
return GetOp(expr,i,Postfix,j);//继续扫描
}
else return '-';//运算符
default:
return expr[(*i)];//括号,乘除
}
}
Precedence GetToken(char op)
{
//返回运算符优先级类型
switch(op){
case '(':return lpr;
case ')':return rpr;
case '+':return plus;
case '-':return minus;
case '*':return times;
case '/':return divide;
case '\0':return eos;
default:return operand;//数字
}
}
/*------辅助函数结束-------*/
运行:
![](https://img-blog.csdnimg.cn/img_convert/8d9bfd1d533fe14f585eee5b70c5fa54.png)
![](https://img-blog.csdnimg.cn/img_convert/b8b158e2aac92817ec9632539f8dc0d5.png)