问题 M: 中缀表达式转后缀表达式
题目描述
输入一个中缀表达式,编程输出其后缀表达式,要求输出的后缀表达式的运算次序与输入的中缀表达式的运算次序相一致。为简单起见,假设输入的中缀表达式由+(加)、-(减)、×(乘)、/(除)四个运算符号以及左右圆括号和英文字母组成,其中算术运算符遵守先乘除后加减的运算规则。假设输入的中缀表达式长度不超过300个字符,且都是正确的,即没有语法错误,并且凡出现括号其内部一定有表达式,即内部至少有一个运算符号。
中缀表达式转后缀表达式的方法:
1.遇到操作数:直接输出(添加到后缀表达式中)
2.栈为空时,遇到运算符,直接入栈
3.遇到左括号:将其入栈
4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,括号不输出。
5.遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
6.最终将栈中的元素依次出栈,输出。
输入
只有一行,为中缀表达式
输出
只有一行,为转换后的后缀表达式
样例输入 Copy
X+A*(Y-B)-Z/F
样例输出 Copy
XAYB-*+ZF/-
实现过程
下面是对代码的详细解析:
-
头文件:
- 包含
<stdio.h>
、<string.h>
和<stdlib.h>
头文件,分别提供输入输出、字符串操作和动态内存分配的功能。
- 包含
-
常量定义:
max
定义了字符数组的最大长度。
-
结构体定义:
cnt
结构体定义了一个栈,包含一个字符数组L
和一个整型top
用于表示栈顶位置。
-
辅助函数
num
:- 该函数用于判断当前字符
ch
和栈顶字符ch2
是否满足运算符优先级的规则。 - 如果当前字符是
+
或-
,并且栈顶字符是+
、-
、*
或/
,则返回1,表示不符合优先级规则。 - 如果当前字符是
*
或/
,并且栈顶字符是*
或/
,则同样返回1。 - 如果字符满足规则,则返回0。
- 该函数用于判断当前字符
-
主函数
main
:- 定义了一个字符数组
ch
用于存储输入的字符串,以及一个cnt
类型的变量leng
用于栈操作。 - 使用
gets
函数读取一个字符串。注意:gets
函数是不安全的,应该使用fgets
函数代替。
- 定义了一个字符数组
-
处理输入字符串:
- 遍历字符串
ch
,对于字母字符,直接打印。 - 对于运算符和括号,根据以下规则处理:
- 如果是右括号
)
,则打印栈中所有字符直到左括号(
,并减少栈顶索引。 - 如果是左括号
(
或者当前运算符优先级高于或等于栈顶运算符,则将当前运算符压栈。 - 如果当前运算符优先级低于栈顶运算符,则打印栈顶运算符,并减少栈顶索引,直到满足优先级规则或栈为空,然后将当前运算符压栈。
- 如果是右括号
- 遍历字符串
-
打印栈中剩余字符:
- 循环直到栈为空,打印栈中剩余的所有字符。
-
程序结束:
- 返回0,表示程序正常结束。
代码逻辑分析:
- 这段代码模拟了一个简单的表达式求值器,它考虑了基本的运算符优先级和括号匹配。
- 它使用了一个栈来存储运算符,并根据运算符的优先级规则来决定何时打印它们。
潜在问题:
- 使用
gets
函数可能导致缓冲区溢出。 - 代码没有处理空格和数字字符,可能需要扩展以支持完整的表达式求值。
改进建议:
- 替换
gets
函数为fgets
,并添加对输入长度的检查。 - 扩展代码以支持数字的处理和更复杂的表达式求值。
- 考虑增加对错误输入的检查和处理,例如不匹配的括号或非法字符。
部分实现
cnt
结构体定义了一个栈,包含一个字符数组
L和一个整型
top` 用于表示栈顶位置。
typedef struct cnt
{
char L[max];
int top;
}cnt;
2.判断当前字符
ch
和栈顶字符ch2
是否满足运算符优先级的规则。
int num(char ch,char ch2)
{
int flag = 1;
if( ch2 == '+' || ch2== '-' )
{ if( ch == '+' || ch == '-' || ch == '*' || ch == '/')
{ flag = 0; return 1; }
}
if( ch2 == '/' || ch2== '*' )
{ if( ch == '*' || ch == '/') { flag = 0; return 1; } }
if( flag ) return 0;
}
3.处理输入字符串
for(j=0;ch[j]!='\0';j++)
{
if((ch[j]>='A'&&ch[j]<='Z')||(ch[j]>='a')&&ch[j]<='z'){printf("%c",ch[j]);}
else if(ch[j]=='+'||ch[j]=='-'||ch[j]=='*'||ch[j]=='/'||ch[j]=='('||ch[j]==')')
{
if(ch[j]==')')
{
while(leng.L[leng.top]!='(')
{printf("%c",leng.L[leng.top]);leng.top--;}
leng.top--;
}
else
{
if(leng.top==-1||(num(leng.L[leng.top],ch[j])==0)||ch[j]=='(')
{leng.top++;leng.L[leng.top]=ch[j];}
else if(num(leng.L[leng.top],ch[j])==1)
{
while(num(leng.L[leng.top],ch[j])==1&&leng.top!=-1)
{printf("%c",leng.L[leng.top]);leng.top--;}
leng.top=leng.top+1;
leng.L[leng.top]=ch[j];
}
}
}
}
while(leng.top!=-1)
{
printf("%c",leng.L[leng.top]);
leng.top--;
}
AC代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define max 300
typedef struct cnt
{
char L[max];
int top;
}cnt;
int num(char ch,char ch2)
{
int flag = 1;
if( ch2 == '+' || ch2== '-' )
{ if( ch == '+' || ch == '-' || ch == '*' || ch == '/')
{ flag = 0; return 1; }
}
if( ch2 == '/' || ch2== '*' )
{ if( ch == '*' || ch == '/') { flag = 0; return 1; } }
if( flag ) return 0;
}
int main()
{
char ch[max];
int i=0,j;
cnt leng;
leng.top=-1;
gets(ch);
for(j=0;ch[j]!='\0';j++)
{
if((ch[j]>='A'&&ch[j]<='Z')||(ch[j]>='a')&&ch[j]<='z'){printf("%c",ch[j]);}
else if(ch[j]=='+'||ch[j]=='-'||ch[j]=='*'||ch[j]=='/'||ch[j]=='('||ch[j]==')')
{
if(ch[j]==')')
{
while(leng.L[leng.top]!='(')
{printf("%c",leng.L[leng.top]);leng.top--;}
leng.top--;
}
else
{
if(leng.top==-1||(num(leng.L[leng.top],ch[j])==0)||ch[j]=='(')
{leng.top++;leng.L[leng.top]=ch[j];}
else if(num(leng.L[leng.top],ch[j])==1)
{
while(num(leng.L[leng.top],ch[j])==1&&leng.top!=-1)
{printf("%c",leng.L[leng.top]);leng.top--;}
leng.top=leng.top+1;
leng.L[leng.top]=ch[j];
}
}
}
}
while(leng.top!=-1)
{
printf("%c",leng.L[leng.top]);
leng.top--;
}
return 0;
}