前缀中缀后缀表达式及其互相转换

计算机中前缀中缀后缀表达式是数据结构栈的重要应用,他们都是对表达式的记法,只是相对位置不一样,顾名思义,前缀表达式指的是符号都在操作数之前,中缀表达式指的是运算符都在操作数之后,而后缀表达式是之后。如:

(a+b)*c-d是中缀表达式

-*+abcd是前缀表达式

ab+c*d-是后缀表达式

中缀表达式是我们常用也是人常见的一种记法,但对于计算机来说处理很复杂,一般都是先转换成前缀或者后缀表达式再进行计算。

一、利用后缀表达式求值:

计算机利用后缀表达式求值过程可分析如下:

以中缀(3+4)*5-6为例,转换成后缀是34+5*6-

从左向右扫描,遇到数字时,将数字压入栈,遇到运算符时候,把栈内前两个数字弹出,进行相应运算,并将计算结果入栈。重复直到表达式右端。

从左向右扫描。将数字3,4入栈;

遇见运算符+,弹出3,4,计算得7入栈

继续扫描,将5入栈

与运算符*,将7,5弹出计算,得35入栈

继续扫描,遇见6入栈

遇见运算符-,弹出两个35,6,计算得29入栈

到最右端,停止,所得结果29

下面关键就是如何把中缀表达式转换成后缀表达式:

1、初始化两个栈,运算符栈S1和数据栈S2

2、从左向右扫描中缀表达式,遇见数字直接入栈S2

3、遇见运算符,将比较运算符与S1栈顶运算符优先级

3-1、如果S1栈顶是空或者是或者是左括号则直接将遇见的运算符入栈S1

3-2、如果S1栈顶不是空也不是左括号,且遇见的运算符比S1内优先级要高,那么将该运算符直接入栈S1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况)

3-3、如果S1栈顶是是右括号或者优先级更大。则将S1内运算符出栈到S2里,再转回3-1

4、遇见括号

4-1、如果是遇见左括号,那么左括号运算符直接入栈S1

4-2、如果是遇见右括号,那么右括号运算符直接入栈S1

5、重复2-4,直至到表达式最右边

6、将S1中剩余运算符弹出到S2

7、 依次弹出S2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)。

将中缀表达式exp转换为后缀表达式,采用了一个op运算符栈,其他的用数组存储。

const int N=20;
vector<char> inexpTopost(char a[],int n){
vector<char> res;
char st[N];
int top=-1;
int i=0;
char c=a[i];
while(c!='\0'){
    switch(c){
    case '(':{top++;st[top]=c;break;}
    case ')':{while(st[top]!='('){res.push_back(st[top]);top--;}
             top--;
             break;
         }
    case '+':
    case '-':{while(top>-1&&st[top]!='('){res.push_back(st[top]);top--;}
             top++;st[top]=c;
             break;
         }
    case '*':
    case '/':{
          while(top>-1&&st[top]!='('&&(st[top]=='*'||st[top]=='/')){res.push_back(st[top]);top--;}
          top++;st[top]=c;
          break;
         }
    default:{
            while(c>='0'&&c<='9')
            {res.push_back(c);i++;c=a[i];}//装入多位的整数
            i--;
            res.push_back('#');//用标识表述数值结束
         }
              }
    i++;c=a[i];
               }
while(top>-1){res.push_back(st[top--]);}
return res;
}

在计算后缀表达式过程中采用一个数值栈st:

float getkey_post(vector<char> arr){
int num_stack[N];int top1=-1;
int len=arr.size();
int i=0;
char c=arr[i];
int s=0;
while(i<len){
    //if(top1-1==-1){cout<<"Out of index";return 0;}
  c=arr[i];
  switch(c){
      case '+':{num_stack[top1-1]=num_stack[top1-1]+num_stack[top1];top1--;break;
           }
      case '-':{num_stack[top1-1]=num_stack[top1-1]-num_stack[top1];top1--;break;
           }
      case '*':{num_stack[top1-1]=num_stack[top1-1]*num_stack[top1];top1--;break;
           }
      case '/':{if(num_stack[top1]==0){cout<<"除数是0"<<endl;return 0;}  
            num_stack[top1-1]=num_stack[top1-1]/num_stack[top1];top1--;break;
           }
      case '#':break;
      default:{   s=0;
          while(c>='0'&&c<='9'){s=10*s+c-'0';i++;c=arr[i];}
          top1++;num_stack[top1]=s;i--;
          }
            } 
  i++;
              }
return num_stack[top1];
}


二、利用前缀表达式求值

以中缀(3+4)*5-6为例,转换成前缀是-*+3456

利用前缀表达式求值:从右向左搜索,遇见数字时入栈,遇见运算符时候出栈前两个数字3+4=7,计算好7再入栈,遇见运算符*,出栈前两个进行计算7*5=35,再入栈,遇见运算符-,出栈进行运算35-6=29,入栈保存结果。

将中缀表达式转换为前缀的过程:

1、初始化两个栈,运算符栈S1和数据栈S2

2、从右向左扫描中缀表达式,遇见数字直接入栈S2

3、遇见运算符,将比较运算符与S1栈顶运算符优先级

3-1、如果S1栈顶是空或者是或者是又括号则直接将遇见的运算符入栈S1

3-2、如果S1栈顶不是空也不是左括号,且遇见的运算符比S1内优先级要高或者一样,那么将该运算符直接入栈S1。

3-3、如果S1栈顶是是左括号或者优先级更大。则将S1内运算符出栈到S2里,再转回3-1

4、遇见括号

4-1、如果是遇见右括号,那么左括号运算符直接入栈S1

4-2、如果是遇见左括号,那么右括号运算符直接入栈S1

5、重复2-4,直至到表达式最左边

6、将S1中剩余运算符弹出到S2

7、 依次弹出S2中的元素并输出,结果即为中缀表达式对应的前缀表达式。

vector<char> inexpTopre(char a[],int n){
vector<char> res;
char num_stack[N];int top1=-1;
char op_stack[N];int top2=-1;
int i=n-1;
char c=a[i];
while(i>=0){
    switch(c){
	case ')':{top2++;op_stack[top2]=c;break;}
	case '(':{while(op_stack[top2]!=')'){top1++;num_stack[top1]=op_stack[top2];top2--;}
		     top2--;
		     break;
		 }
	case '+':
	case '-':{while(top2>-1&&op_stack[top2]!=')'&&(op_stack[top2]=='*'||op_stack[top2]=='/')){top1++;num_stack[top1]=op_stack[top2];top2--;}
		  top2++;op_stack[top2]=c;
		  break;
		 }
	case '*':
	case '/':{top2++;op_stack[top2]=c;
		     break;
		 }
	default:{
		 while(c>='0'&&c<='9'){top1++;num_stack[top1]=c;i--;c=a[i];}
                top1++;num_stack[top1]='#';i++;
		}
              }
    i--;if(i<0)break;
    c=a[i];
              }
while(top2>-1){top1++;num_stack[top1]=op_stack[top2--];}
for(i=top1;i>=0;i--)
    res.push_back(num_stack[i]);
return res;
}
最后是根据前缀序列求出最终结果:

int getvalue(char str[]){
int s=0;
int i,j;
int len=0;
for(i=0;str[i]!='\0';i++)
   len++;
for(i=0,j=len-1;i<j;i++,j--)
{char t=str[i];str[i]=str[j];str[j]=t;}
i=0;
while(str[i]!='\0'){
    s=s*10+str[i]-'0';
    i++;
                    }
return s;
}
float getkey_pre(vector<char>arr){
int st[N],top=-1;
int len=arr.size();
int i=len-1,j;
char c=arr[i];
int s;
char tmp[N];
while(i>=0){
    c=arr[i];
    switch(c){
	case '+':{st[top-1]=st[top]+st[top-1];top--;break;}
	case '-':{st[top-1]=st[top]-st[top-1];top--;break;}
        case '*':{st[top-1]=st[top]*st[top-1];top--;break;}
	case '/':{
		     if(st[top-1]==0){cout<<"除数是0";return 0;}
                     st[top-1]=st[top]/st[top-1];top--;break;
		 }
	case '#':break;
	default:{
		    s=0;
		    j=0;
		    while(c>='0'&&c<='9'){tmp[j++]=c;i--;c=arr[i];}
		    tmp[j]='\0';s=getvalue(tmp);
		    top++;st[top]=s;i++;
		}

             }
    i--;
            }
return st[top];
}



  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值