1. 程式人生 > >字首中綴字尾表示式及其互相轉換

字首中綴字尾表示式及其互相轉換

計算機中字首中綴字尾表示式是資料結構棧的重要應用,他們都是對錶達式的記法,只是相對位置不一樣,顧名思義,字首表示式指的是符號都在運算元之前,中綴表示式指的是運算子都在運算元之後,而後綴表示式是之後。如:

(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];
}