【转】算术表达式中缀形式转后缀形式,并基于后缀式和栈进行计算

来源:互联网 发布:上能电气怎么样 知乎 编辑:程序博客网 时间:2024/05/22 09:03

原文地址:(该文章也得非常好!要原创作者致敬!)

http://blog.csdn.net/liuzhanchen1987/article/details/7387480


对于一个中缀表达式 a+b*c*(d-e/f) 转换成后缀是这样的形式 abc*def/-+
后缀表达式是相当有用处的,转换成后缀表达式后求值会简单很多.那么该如何转换呢? 

网上关于这方面的资料一搜一大把,每本数据结构的书中都会提及这个算法,在这个算法中,用到 栈 这个数据结构. 

1,关键是比较运算符的优先级,谁的优先级高,谁就出现在前面上面的表达式中,有括号的时候括号优先级最高,*/次之,+-最后. 在上面的表达式中+的优先级不如*的高,因此,在后缀表达式中*出现在+前面,


2,遇到操作数的时候总是直接输出,不做任何比较 

3,遇到左括号总是直接入栈,遇到右括号的时候总是弹栈,一直弹到遇到一个左括号 

4,遇到操作符的时候就先将这个操作符和它前面的操作符比较优先级,假如高于前面的优先级,先将它压栈,假如低于或等于前面的操作符的优先级,就把前面的优先级比它高的或相等的顺序弹出来, 一直弹到遇到优先级比它还低的或者到了栈顶 ,然后该操作符再压入栈。

知道以上四个规则就可以设计代码实现了,代码如下:

[cpp] view plaincopy
  1. #include<iostream>  
  2. #include<string>  
  3. #include<stack>  
  4. #include<map>  
  5. using namespace std;  
  6. void InerStringDevide(string InerStr,string DeviStr[],int &num)  
  7. {  
  8.     int count,i;  
  9.     int numbe=InerStr.size();  
  10.     for(i=0;i<numbe;i++)  
  11.         DeviStr[i][0]='\0';  
  12.     count=0;  
  13.     for(i=0;i<numbe;)  
  14.     {  
  15.         if(InerStr[i]=='+'||InerStr[i]=='-'||InerStr[i]=='*'||  
  16.             InerStr[i]=='/'||InerStr[i]=='%'||InerStr[i]=='^'  
  17.             ||InerStr[i]=='('||InerStr[i]==')')  
  18.         {  
  19.             DeviStr[count].push_back(InerStr[i]);  
  20.             count++;  
  21.             i++;  
  22.         }  
  23.         else  
  24.         {  
  25.             while(InerStr[i]!='+'&&InerStr[i]!='-'&&InerStr[i]!='*'&&  
  26.             InerStr[i]!='/'&&InerStr[i]!='%'&&InerStr[i]!='^'  
  27.             &&InerStr[i]!='('&&InerStr[i]!=')')  
  28.             {  
  29.                 DeviStr[count].push_back(InerStr[i]);  
  30.                 i++;  
  31.                 if(i>=numbe)  
  32.                     break;  
  33.             }  
  34.             count++;  
  35.         }  
  36.     }  
  37.     num=count;  
  38. }  
  39. void InerTreeToPostTree(string InerStr,string &PostStr)  
  40. {  
  41.     PostStr[0]='\0';  
  42.     map<char,int>OpC;  
  43.     typedef map<char,int>::value_type ValType;  
  44.     OpC.insert(ValType('+',1));  
  45.     OpC.insert(ValType('-',1));  
  46.     OpC.insert(ValType('*',2));  
  47.     OpC.insert(ValType('/',2));  
  48.     OpC.insert(ValType('%',2));  
  49.     OpC.insert(ValType('^',3));  
  50.     OpC.insert(ValType('(',-1));  
  51.     OpC.insert(ValType(')',0));  
  52.     int num,i,j,StrNum;  
  53.     num=InerStr.size();  
  54.     string *DevedeStr=new string[num];  
  55.     InerStringDevide(InerStr,DevedeStr,StrNum);  
  56.   
  57.     stack<char> ChStack;  
  58.     int count=0;  
  59.     for(int i=0;i<StrNum;i++)  
  60.     {  
  61.         //如果输入的字符串是操作符  
  62.         if(DevedeStr[i][0]=='+'||DevedeStr[i][0]=='-'||DevedeStr[i][0]=='*'||  
  63.             DevedeStr[i][0]=='/'||DevedeStr[i][0]=='%'||DevedeStr[i][0]=='^'  
  64.             ||DevedeStr[i][0]=='('||DevedeStr[i][0]==')')  
  65.         {  
  66.             //如果操作符栈中为空可以直接将操作符入栈  
  67.             if(ChStack.empty())  
  68.             {  
  69.                 ChStack.push(DevedeStr[i][0]);  
  70.             }  
  71.             //如果非空要根据操作符的优先级及其类别进行判断并分类入栈  
  72.             else  
  73.             {  
  74.                 char TopCh=ChStack.top();  
  75.                 //如果是(则直接入栈  
  76.                 if(OpC[DevedeStr[i][0]]==-1)  
  77.                 {  
  78.                     ChStack.push(DevedeStr[i][0]);  
  79.                 }  
  80.                 //如果操作符优先级大于栈中当前操作符直接入栈  
  81.                 else if(OpC[TopCh]<OpC[DevedeStr[i][0]])  
  82.                 {  
  83.                     ChStack.push(DevedeStr[i][0]);  
  84.                 }  
  85.                 //否则按操作符的类别有区别的处理  
  86.                 else  
  87.                 {  
  88.                     //如果遇到)则操作符出栈并入字符串  
  89.                     if(OpC[DevedeStr[i][0]]==0)  
  90.                     {  
  91.                         TopCh=ChStack.top();  
  92.                         while(OpC[TopCh]!=-1)  
  93.                         {  
  94.                             if(!PostStr.empty())  
  95.                             {  
  96.                                 PostStr.push_back(' ');  
  97.                             }  
  98.                             PostStr.push_back(TopCh);  
  99.                             ChStack.pop();  
  100.                             TopCh=ChStack.top();  
  101.                         }  
  102.                         ChStack.pop();  
  103.                         TopCh=ChStack.top();  
  104.                     }  
  105.                     else  
  106.                     {  
  107.                         while(OpC[TopCh]>=OpC[DevedeStr[i][0]]&&OpC[TopCh]!=-1)  
  108.                         {  
  109.                             if(!PostStr.empty())  
  110.                             {  
  111.                                 PostStr.push_back(' ');  
  112.                             }  
  113.                             PostStr.push_back(TopCh);  
  114.                             ChStack.pop();  
  115.                             if(!ChStack.empty())  
  116.                                 TopCh=ChStack.top();  
  117.                             else  
  118.                                 break;  
  119.                         }  
  120.                         ChStack.push(DevedeStr[i][0]);  
  121.                     }  
  122.                 }  
  123.             }  
  124.         }  
  125.         //如果输入的字符串是数字  
  126.         else  
  127.         {  
  128.             int DevideSize=DevedeStr[i].size();  
  129.             if(!PostStr.empty())  
  130.             {  
  131.                 PostStr.push_back(' ');  
  132.             }  
  133.             for(int j=0;j<DevideSize;j++)  
  134.             {  
  135.                 PostStr.push_back(DevedeStr[i][j]);  
  136.             }  
  137.         }  
  138.     }  
  139.     while(!ChStack.empty())  
  140.     {  
  141.         if(!PostStr.empty())  
  142.         {  
  143.             PostStr.push_back(' ');  
  144.         }  
  145.         PostStr.push_back(ChStack.top());  
  146.         ChStack.pop();  
  147.     }  
  148. }  


以上为头文件InerTreeToPostTree.h。该文件的 作用是输入中缀字符串,输出后缀字符串,其中中缀字符串不带空格,而后缀字符串带空格。头文件中的另一个函数是将字符串分为字符串数组,该数组中存储数字和运算符。

[cpp] view plaincopy
  1. #include<iostream>  
  2. #include<stack>  
  3. #include<string>  
  4. using namespace std;  
  5. void StringDevide(string str,int &num,string st1[])  
  6. {  
  7.     for(int i=0;i<100;i++)  
  8.         st1[i][0]='\0';  
  9.     int n=str.size();  
  10.     int j=0,count=0;  
  11.     for(int i=0;i<n;i++)  
  12.     {  
  13.         if(str[i]!=' ')  
  14.         {  
  15.             st1[count].push_back(str[i]);  
  16.         }  
  17.         else  
  18.         {  
  19.             count++;  
  20.         }  
  21.     }  
  22.     num=count+1;  
  23. }  
  24. void StringToNum(string str,int &num)  
  25. {  
  26.     num=0;  
  27.     int n=str.size();  
  28.     for(int i=0;i<n;i++)  
  29.     {  
  30.         num=num*10;  
  31.         num+=str[i]-'0';  
  32.     }  
  33. }  
  34. class InterTreeComputer  
  35. {  
  36. private:  
  37.     //要计算的表达式  
  38.     string m_expresion;  
  39.     //将数字存储到栈中  
  40.     stack<int> m_num;  
  41.   
  42. public:  
  43.     InterTreeComputer(string expression):m_expresion(expression)  
  44.     {}  
  45.     //判定某一操作符是否是运算符  
  46.     bool IsOperator(char ch)const;  
  47.     //获取要计算的两个运算数  
  48.     void GetOperands(int &left,int &right);  
  49.     //对获取的两个数按照符号ch进行计算  
  50.     int computer(int left,int right,char ch)const;  
  51.     //获取表达式  
  52.     string GetPostoperation()const;  
  53.     void SetPostoperator();  
  54.     //计算表达式并返回结果  
  55.     int Evaluate();  
  56. };  
  57. bool InterTreeComputer::IsOperator(char ch)const  
  58. {  
  59.     switch(ch)  
  60.     {  
  61.     case '+':  
  62.     case '-':  
  63.     case '*':  
  64.     case '/':  
  65.     case '%':  
  66.     case '^':  
  67.         return 1;  
  68.     default:  
  69.         return 0;  
  70.     }  
  71. }  
  72. void InterTreeComputer::GetOperands(int &left,int &right)  
  73. {  
  74.     if(m_num.empty())  
  75.     {  
  76.         cout<<"num stack is empty!";  
  77.         return ;  
  78.     }  
  79.     right=m_num.top();  
  80.     m_num.pop();  
  81.     if(m_num.empty())  
  82.     {  
  83.         cout<<"the expression is wrong!"<<endl;  
  84.         return ;  
  85.     }  
  86.     left=m_num.top();  
  87.     m_num.pop();  
  88. }  
  89. int InterTreeComputer::computer(int left,int right,char ch)const  
  90. {  
  91.     switch(ch)  
  92.     {  
  93.     case '+':  
  94.         return left+right;  
  95.         break;  
  96.     case '-':  
  97.         return left-right;  
  98.         break;  
  99.     case '*':  
  100.         return left*right;  
  101.         break;  
  102.     case '/':  
  103.         if(right==0)  
  104.         {  
  105.             cout<<"the expression is wrong"<<endl;  
  106.             return -1;  
  107.         }  
  108.         return left/right;  
  109.         break;  
  110.     case '%':  
  111.         return left%right;  
  112.         break;  
  113.     case '^':  
  114.         if(left==0&&right==0)  
  115.         {  
  116.             cout<<"the expression is wrong"<<endl;  
  117.             return -1;  
  118.         }  
  119.         int value=1;  
  120.         while(right>0)  
  121.         {  
  122.             value*=left;  
  123.             right--;  
  124.         }  
  125.         return value;  
  126.         break;  
  127.     }  
  128. }  
  129. string InterTreeComputer::GetPostoperation()const  
  130. {  
  131.     return m_expresion;  
  132. }  
  133. void InterTreeComputer::SetPostoperator()  
  134. {}  
  135. int InterTreeComputer::Evaluate()  
  136. {  
  137.     string *str=new string[100];  
  138.     int num;  
  139.     StringDevide(m_expresion,num,str);  
  140.     for(int i=0;i<num;i++)  
  141.     {  
  142.         if(str[i][0]=='+'||str[i][0]=='-'||str[i][0]=='*'||str[i][0]=='/'  
  143.             ||str[i][0]=='%'||str[i][0]=='^')  
  144.         {  
  145.             char ch=str[i][0];  
  146.             int left,right;  
  147.             GetOperands(left,right);  
  148.             int number=computer(left,right,ch);  
  149.             m_num.push(number);  
  150.         }  
  151.         else  
  152.         {  
  153.             int numb=0;  
  154.             StringToNum(str[i],numb);  
  155.             m_num.push(numb);  
  156.         }  
  157.     }  
  158.     return m_num.top();  
  159. }  


以上代码为InerTreeComputer.h头文件,该头文件的作用是输入后缀表达式并计算该表达式的值。

[cpp] view plaincopy
  1. #include<iostream>  
  2. using namespace std;  
  3. #include<string>  
  4. #include<stack>  
  5. #include"InterTreeComputer.h"  
  6. #include"InerTreeToPostTree.h"  
  7. int main()  
  8. {  
  9.     string str="3*(4-2^5)+6";  
  10.     string st1="2 3 ^ 1 +";  
  11.     string st2="2 2 3 ^ ^ 4 /";  
  12.     string StrRe;  
  13.     InerTreeToPostTree(str,StrRe);  
  14.     InterTreeComputer Comp(StrRe);  
  15.     cout<<Comp.GetPostoperation()<<endl;  
  16.     cout<<Comp.Evaluate()<<endl;  
  17.     return 0;  
  18. }  


测试文件对以上两个头文件进行了测试。

原创粉丝点击