前/中/后缀的那些事儿
自然表达式转换为前/中/后缀表达式。首先将自然表达式按照优先级顺序,构造出与表达式相对应的二叉树,然后对二叉树进行前/中/后缀遍历,即得到前/中/后缀表达式。
由树的遍历——
① 前序遍历:根-左-右
② 中序遍历:左-根-右
③ 后序遍历:左-右-根
可以得出:
前缀表达式:前序遍历
中缀表达式:中序遍历
后缀表达式:后序遍历
中缀表达式按操作符的优先级进行计算(后面代码实现只包括+、-、*、\,小括号),即数学运算。 后缀表达式中只有操作数和操作符。操作符在两个操作数之后。它的计算规则非常简单,严格按照从左到右的次序依次执行每一个操作。每遇到一个操作符,就将前面的两个数执行相应的操作。
由后缀表达式计算中缀表达式原理:计算机处理后缀表达式求值问题是比较方便的,即将遇到的操作数暂存于一个操作数栈中,凡是遇到操作数,便从栈中pop出两个操作数,并将结果存于操作数栈中,直到对后缀表达式中最后一个操作数处理完,最后压入栈中的数就是后最表达式的计算结果。
中缀表达式转换为等价的后缀表达式 :
我们把平时所用的标准四则将中缀表达式转化为后缀表达式运算表达式,即“9+(3-1)*3+10/2"叫做中缀表达式。因为所有的运算符号都在两数字的中间,现在我们的问题就是中缀到后缀的转化。
中缀表达式“9+(3-1)*3+10/2”转化为后缀表达式“9 3 1-3*+ 10 2/+”
规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
算法描述:
将中缀表达式转换为等价的后缀表达式的过程要使用一个栈放“(”,具体可以按照下面的方式进行。
(1)从左到右依次扫描中缀表达式的每一个字符,如果是数字字符和圆点“.”则直接将它们写入后缀表达式中。
(2)如果遇到的是开括号“(”,则将它们压入一个操作符栈(不需要与栈顶操作符相比较),它表明一个新的计算层次的开始,在遇到和它匹配的闭括号“)”时,将栈中的元素弹出来并放入后缀表达式中,直到栈顶元素为“(”时,将栈顶元素“(”弹出(不需要加入后缀表达式),表明这一层括号内的操作处理完毕。
(3)如果遇到的是操作符,则将该操作符和操作符栈顶元素比较:
1、当所遇到的操作符的优先级小于或等于栈顶元素的优先级时,则取 出栈顶元素放入后缀表达式,并弹出该栈顶元素,反复执行直到当前操作符的优先级大于栈顶元素的优先级;
2、当所遇到的操作符的优先级大于栈顶元素的优先级的时则将它压入栈中。 即可以概括为胆小的怕胆大的,胆大的怕不要命的——” ) ”.
下面我们来具体看看这个过程。
1. 初始化一空栈,用来对符号进出栈使用。
2. 第一个字符是数字9,输出9,后面是符号“+”,进栈。
3. 第三个字符是“(”,依然是符号,因其只是左括号,还未配对,故进栈。
4. 第四个字符是数字3,输出,总表达式为9 3,接着是“-”进栈。
5. 接下来是数字1,输出,总表达式为9 3 1,后面是符号“)”,此时,我们需要去匹配此前的“(”,所以栈顶依次出栈,并输出,直到“(”出栈为止。此时左括号上方只有“-”,因此输出“-”,总的输出表达式为9 3 1 -
6. 接着是数字3,输出,总的表达式为9 3 1 - 3 。紧接着是符号“*”,因为此时的栈顶符号为“+”号,优先级低于“*”,因此不输出,进栈。
7. 之后是符号“+”,此时当前栈顶元素比这个“+”的优先级高,因此栈中元素出栈并输出(没有比“+”号更低的优先级,所以全部出栈),总输出表达式为 9 3 1 - 3 * +.然后将当前这个符号“+”进栈。也就是说,前6张图的栈底的“+”是指中缀表达式中开头的9后面那个“+”,而下图中的栈底(也是栈顶)的“+”是指“9+(3-1)*3+”中的最后一个“+”。
8. 紧接着数字10,输出,总表达式变为9 3 1-3 * + 10。
9. 最后一个数字2,输出,总的表达式为 9 3 1-3*+ 10 2
10. 因已经到最后,所以将栈中符号全部出栈并输出。最终输出的后缀表达式结果为 9 3 1-3*+ 10 2/+
·
从刚才的推导中你会发现,要想让计算机具有处理我们通常的标准(中缀)表达式的能力,最重要的就是两步:
·
1. 将中缀表达式转化为后缀表达式(栈用来进出运算的符号)。
2. 将后缀表达式进行运算得出结果(栈用来进出运算的数字)。
整个过程,都充分利用了找的后进先出特性来处理,理解好它其实也就理解好了栈这个数据结构。
+++++++++++++++++++++++++++++++++++++++主要代码如下++++++++++++++++++++++++++++++++++++++++++++
1.中缀转后缀
int pre(char a) //操作符优先级比较
{
if(a == '=' || a == '(')
return 0;
else if(a == '+' || a == '-')
return 1;
else if(a == '*' )
return 2;
else if(a=='^')
return 3;
}
void change(string str)
{
int len = str.length();
for(int i = 0 ; i <len;++i)
{
if(str[i] >= '0' && str[i] <= '9') //操作数直接存入ans
ans.push_back(str[i]);
else if(str[i] == '(') //左括号入栈
ope.push(str[i]);
else if(str[i] == ')') //右括号,将匹配的左括号内容存入ans,左括号出栈
{
while (ope.top() != '(')
{
ans.push_back(ope.top());
ope.pop();
}
ope.pop(); //左括号出栈
}
else if(pre(str[i]) > pre(ope.top())) //优先级大于栈顶元素则入栈
ope.push(str[i]);
else //小于栈顶元素
{
while(pre(str[i]) <= pre(ope.top()))
{
ans.push_back(ope.top());
ope.pop();
}
ope.push(str[i]);
}
}
while(ope.top() != '=') //其余操作符存入后缀表达式中
{
ans.push_back(ope.top());
ope.pop();
}
}
2.后缀表达式的计算
long long strnum(string s)
{
long long num;
stringstream ss(s);
ss>>num;
return num;
}
long long work(string s)//后缀表达式的计算
{
string ss;
ss="";
memset(sta,0,sizeof(sta));top=0;
for(int i=0;i<s.size();i++)
{
if(s[i]>='0'&&s[i]<='9')
ss+=s[i];
else
{
if(s[i]==' ')
{
top++;
sta[top]=strnum(ss);
ss="";
}
else
{
if(s[i]=='-')
{
int s1,s2;
s2=sta[top];
if(top>0)
{top--;
s1=sta[top];
s1-=s2;
sta[top]=s1;}
continue;
}
if(s[i]=='+')
{
int s1,s2;
s2=sta[top];
if(top>0)
{top--;
s1=sta[top];
s1+=s2;
sta[top]=s1;}
continue;
}
if(s[i]=='*')
{
int s1,s2;
s1=sta[top];if(top>0) top--;
s2=sta[top];
s1*=s2;
sta[top]=s1;
continue;
}
if(s[i]=='^')
{
int s1,s2;
s1=sta[top];if(top>0) top--;
s2=sta[top];
int z=1;
for(int i=1;i<=s1;i++)
z*=s2;
sta[top]=z;
continue;
}
}
}
}if(top==0)return strnum(ss);
else return sta[top];
}
本文参考一下博客内容:
——http://www.nowamagic.net/librarys/veda/detail/2307
——http://www.blogjava.net/wxqxs/archive/2009/05/21/277336.html
——http://blog.csdn.net/niushuai666/article/details/6702964
对以上作者表示衷心的感谢!
另:转载请注明以上博客信息,及本博客信息