C++学习之(栈) 实践之(逆波兰公式)

来源:互联网 发布:凸优化 求解 编辑:程序博客网 时间:2024/05/21 09:07

栈(statck)这种数据结构在计算机中是相当出名的。栈中的数据是先进后出的(First In Last Out, FILO)。栈只有一个出口,允许新增元素(只能在栈顶上增加)、移出元素(只能移出栈顶元素)、取得栈顶元素等操作。在STL中,栈是以别的容器作为底部结构,再将接口改变,使之符合栈的特性就可以了。因此实现非常的方便。在STL中栈一共就5个常用操作函数(top()、push()、pop()、 size()、empty() ),很好记的。

 
#include <iostream>#include <vector>#include <stack>#include <list>using namespace std;int main(){//定义栈 使用list作为容器stack<int,list<int>> a; stack<int,vector<int>> b; int i;//压入栈数据for(i = 0;i < 10;i++){a.push(i);b.push(i);}//输出栈size的大小cout<<"a stack size : " << a.size()<<endl;//取栈项数据并将数据弹出栈  cout<<"a 中的数据:";while(!a.empty()){   cout<<a.top()<<" ";   //栈顶元素弹出栈   a.pop();}cout<<endl;cout<<"b 中的数据:";while(!b.empty()){   cout<<b.top()<<" ";   //栈顶元素弹出栈   b.pop();}system("pause");    return 0;}


栈的实践使用:逆波兰公式

表达式一般由操作数(Operand)、运算符(Operator)组成,例如算术表达式中,通常把运算符放在两个操作数的中间,
这称为中缀表达式(Infix Expression),如A+B。
波兰数学家Jan Lukasiewicz提出了另一种数学表示法,它有两种表示形式:
把运算符写在操作数之前,称为波兰表达式(Polish Expression)或前缀表达式(Prefix Expression),如+AB;
把运算符写在操作数之后,称为逆波兰表达式(Reverse Polish Expression)或后缀表达式(Suffix Expression),如AB+;
其中,逆波兰表达式在编译技术中有着普遍的应用。
 
算法:
一、 将中缀表达式转换成后缀表达式算法:
1、从左至右扫描一中缀表达式。
2、若读取的是操作数,则判断该操作数的类型,并将该操作数存入操作数堆栈
3、若读取的是运算符
  (1) 该运算符为左括号"(",则直接存入运算符堆栈。
  (2) 该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。
  (3) 该运算符为非括号运算符:
      (a) 若运算符堆栈栈顶的运算符为括号,则直接存入运算符堆栈。
      (b) 若比运算符堆栈栈顶的运算符优先级高或相等,则直接存入运算符堆栈。
      (c) 若比运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压入运算符堆栈。
4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。
 
二、逆波兰表达式求值算法:

      对后缀表达式求值比直接对中缀表达式求值简单。在后缀表达式中,不需要括号,而且操作符的优先级也不再起作用了。您可以用如下算法对后缀表达式求值:

  1. 初始化一个空堆栈
  2. 从左到右读入后缀表达式
  3. 如果字符是一个操作数,把它压入堆栈。
  4. 如果字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。
  5. 到后缀表达式末尾,从堆栈中弹出结果。若后缀表达式格式正确,那么堆栈应该为空。
<pre name="code" class="cpp">#include <iostream>#include <stack>#include <list>using namespace std;//声明函数bool isOperand(char c);bool isOpertor(char c);bool ComaprePriority(char op1,char op2);int getPriorityValue(char c);int Operate(char op, int operand1, int operand2);//判断是否为数字bool isOperand(char c){  return ( c == '0' || c == '1' || c == '2' || c == '3' || c == '4' ||                               c == '5' || c == '6' || c == '7' || c == '8' || c == '9' );}//判断是否为运算符bool isOpertor(char c){   return ( c == '+' || c == '-' || c == '*' || c == '/' ||                               c == '(' || c == ')' );}//判断运算符优先级大小 op1优先级高于或者等于op2返回truebool ComaprePriority(char op1,char op2){return (getPriorityValue(op1) >= getPriorityValue(op2)) ;}//获取运算符优先级int getPriorityValue(char c){int prioityValue;switch(c){case '+ ':prioityValue = 1;break;case '-':prioityValue = 1;break;case '*':prioityValue = 2;break;case '/':prioityValue = 2;break;default:prioityValue = 0;}return prioityValue;}int Operate(char op, int operand1, int operand2){      switch(op)      {      case '+':            return operand1 + operand2;      case '-':            return operand1 - operand2;      case '*':            return operand1 * operand2;      case '/':            return operand1 / operand2;      default:            return -1;      }}int main(){//定义栈 使用list作为容器stack<char> operand; stack<char> opertor; char str[20] = "(2+4)*4+1";//压入栈数据int length = strlen(str);for(int i = 0;i < length;i++){char c = str[i];cout<<c<<" ";//判断是否为操作数if (isOperand(c)){operand.push(c);}else{//为运算符//若运算符为"("直接存入到运算符栈中if( c == '('){opertor.push(c);}else if(c == ')'){//该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。while(opertor.top() != '('){char op = opertor.top();opertor.pop();operand.push(op);}//将'('出栈opertor.pop();}else{ // 该运算符为非括号运算符:  // (a) 若运算符堆栈栈顶的运算符为括号,则直接存入运算符堆栈。  //考虑栈顶为空的情况  if(opertor.empty())  {opertor.push(c);continue;  }  if(opertor.top() == '(')  {opertor.push(c);  }  else  {  //(b) 若比运算符堆栈栈顶的运算符优先级高或相等,则直接存入运算符堆栈。  if(ComaprePriority(c,opertor.top()))  {opertor.push(c);  }  else  {// (c) 若比运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压入运算符堆栈。char op = opertor.top();operand.push(op);opertor.pop();opertor.push(c);  }// if(ComaprePriority(c,opertor.top()))  }//end  if(opertor.top() == '(')}//end if( c == '(')}//end if (isOperand(c))}//end for//4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。while(!opertor.empty()){char op = opertor.top();operand.push(op);opertor.pop();}//cout<<endl<<"转换后的逆波兰表达式:";//输出转换后的逆波兰表达式//while(!operand.empty())//{//cout<<operand.top()<<" ";//operand.pop();//}//计算逆波兰表达式stack<char> stackOper;stack<int> stackresult;//计算使用栈//上面计算后的栈是反着的 把它倒转过来计算while(!operand.empty()){//cout<<operand.top()<<" ";char op = operand.top();stackOper.push(op);operand.pop();}//计算逆波兰表达式while(!stackOper.empty()){char op = stackOper.top();//如果字符是一个操作数,把它压入堆栈。 if (isOperand(op)){int num ;num = atoi(&op);stackresult.push(num);}else{//如果字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。int number1 = stackresult.top();stackresult.pop();int number2 = stackresult.top();stackresult.pop();//弹出两个操作符执行运算int result =  Operate(op,number1,number2);stackresult.push(result);}stackOper.pop();}//输出计算结果cout<<" = " <<  stackresult.top()<<endl;system("pause");    return 0;}

 

 

 

 

原创粉丝点击