中缀后缀
日常生活中,我们都是使用中缀表达式,如8*(5+3)这样的,这样的式子可以画成一个二叉树,而二叉树的遍历方式有三种,分别对应着三种表达式方式。
(感觉说多了,再说后面二叉树没东西讲了)
所以上面的式子可以写成8 5 3+ * ,虽然看着很诡异,但是要知道,对于计算机来说,看中缀表达式比看十进制难受多了(栈的应用1——数制转换),因为:
后缀表达式可以避免括号
游戏规则
在这道题里面,可以输入大小写的单字母变量,以及双目四则运算(加减乘除)还有括号,目的是将这个转换成一个后缀表达式,以去掉括号。
先分析一下,因为是去掉括号,所以需要匹配到一对括号然后一起删掉,那么问题来了,如果你在读入第一对括号的时候,正等着他的另一半,却等到了别人,这就尴尬了,所以呢,要先将他请到一边,(看看标题,看看标题),这个时候就是栈的用处了。
原则:
- 读到字母就输出;
- 左括号直接压栈别犹豫,犹豫就会白给;
- 加减乘除的运算符,要比较和栈顶元素的优先级,(栈空直接压入)要是高就直接压入,如果低就需要一直出栈直到栈空或者栈顶元素的优先级低于当前。
- 读到右括号的时候,需要将站内元素出栈直到碰到左括号,把两个一起删了。
- 结束读入,将栈清空,准确是全部出栈,可不是直接删了
那么问题来了,优先级相同呢?
这就是个坑!
为啥,(因为lz被这东西折磨了两天,代码数据反复横跳),因为前面说了这个东西可以用二叉树表示,而中缀就是一个中序遍历的结果。
而只给出二叉树的中序遍历不能唯一确定二叉树,后期给出。
所以后缀,也就是后序的结果不唯一,就差这这些优先级相同上面。
- 在比较入栈
- 出栈比较优先级
这两个位置会不一样。
贴代码
#include <iostream>
#include <cstring>
using namespace std;
struct link
{
char data;
struct link* next;
};
void get_in(struct link* head,char data)//入栈
{
struct link* pr=(struct link*)malloc(sizeof(struct link));
pr->next=head->next;
head->next=pr;
pr->data=data;
}
void get_out(struct link* head)//出栈
{
struct link* pr=head->next;
head->next=pr->next;
cout<< pr->data;
free(pr);
}
int judge(struct link* head)//判断栈空
{
if(head->next!=NULL)
return 1;//非空
else
return 0;
}
int compare(struct link* head,char data)//判断栈顶和当前的优先级大小
{
int h,d;//栈顶元素分四级,左括号、加减、乘除、右括号。
if(head->next->data=='*'||head->next->data=='/')
h=1;
else if(head->next->data=='+'||head->next->data=='-')
h=0;
else if(head->next->data=='(')
h=-1;
else
h=2;
if(data=='*'||data=='/')
d=1;
else
d=0;
if(d>h)//当前大于栈顶
return 1;
else if(d==h)//相等
return 0;
else
return -1;
}
void work(string in)
{
int length=in.size();//先将字符串类转化成数组
char a[length+1];
strcpy(a,in.c_str());
struct link* head=(struct link*)malloc(sizeof(struct link));//操作符栈
head->next=NULL;
for(int i=0;i<length;i++)
{
if((a[i]>64&&a[i]<91)||(a[i]>96&&a[i]<123))//字母
{
cout<< a[i];
}
else if(a[i]==40)//(
{
get_in(head,'(');
}
else if(a[i]==43||a[i]==45||a[i]==42||a[i]==47)// +-*/
{
if(!judge(head))//操作符栈空
get_in(head,a[i]);//压栈
else if(compare(head,a[i])==1 || compare(head,a[i])==0)//当前的操作符优先级高于等于操作符栈顶元素
{
get_in(head,a[i]);//压栈
}
else
{
while(judge(head)&&(compare(head,a[i])==-1||compare(head,a[i])==0))//当前优先级低,要让比他高的都出来
{
get_out(head);
}
get_in(head,a[i]);//再压入
}
}
else // )
{
while(judge(head)&&head->next->data!='(')
{
get_out(head);//将操作符栈的内容弹出到字母栈
}
struct link* pr=head->next;//这个是左括号
head->next=pr->next;
free(pr);//'('不需要进入字母栈
}
}
while(head->next)
{
get_out(head);//最后操作符栈剩的都压入字母栈来里面
}
free(head);
}
int main()
{
string in;
cin>>in;
work(in);
return 0;
}