C++用后缀表达式(逆波兰)求四则表达式值,采用STL中的stack

简介:

20 世纪50 年代, 波兰逻辑学家JanLukasiewicz ,想到了一种不需要括号的后缀表达法,我们也把它称为逆波兰( Reverse Polish Notation, RPN) 表示,对于"如9 + (3 -1 ) X3 +10-/2 " ,如果要用后缀表示法应该是: "9 3 1-3*+10 2 / + " ,这样的表达式称为后缀表达式.

中缀表达式转后缀表达式规则: 

从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分; 若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出, 并将当前符号进栈,一直到最终输出后缀表达式为止。

后缀表达式计算求值:

从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进钱, 一直到最终获得结果。

示例代码:

<pre name="code" class="cpp">//============================================================================
// Name        : SiZeCal.cpp
// Author      : guo
// Version     : 0.1
// Copyright   : nupt
// Description : 四则运算表达式求值,输入整数的四则运算表达式,计算其值。
//				PS:此版本不支持输入中有空格!
//============================================================================

#include <iostream>
#include <stack>		//use STL
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;

const int MAXSIZE=256;


int InfixToPostfix(char *infix,char *postfix);
double Calculate(char *arr);
int main() {
	cout << "四则运算,请输入运算式:" << endl; // prints 四则运算
	char in[MAXSIZE]={0};
	char postfix[MAXSIZE]={'\0'};
	fgets(in,MAXSIZE,stdin);
	if(InfixToPostfix(in,postfix)!=1)
	{	cout<<"InfixToPostfix wrong!!!";
		return -1;
	}
	puts(in);puts(postfix);
	cout<<Calculate(postfix);
	return 0;
}
/*
将中缀表达式转换为后缀表达式
参数:infix 指向中缀表达式,以回车键即\n结尾。
postfix 指向后缀表达式临时缓冲区,用来存放转换后的结果。
附转换规则:从左到右遍历中缀表达式的每个数字和符号,若是数字则直接保存在postfix数组中;若是符号,则判断其与栈顶符号的优先级,是右括号或者优先级不大于栈顶符号,则栈顶元素依次出栈并输出,直到遇到左括号或者栈空时,才将刚才的那个符号入栈。
*/
int InfixToPostfix(char *infix,char *postfix)
{
  stack<char> s;
  char c,e;
  int j=0,i=0;
  c=*(infix+i); //取出中缀表达式中的第一个字符
  i++;
  while('\n'!=c) //遇到换行符,表示转换结束
  {
       while(c>='0'&&c<='9') //先判断一下取出的字符是否是数字,如果是数字的话,则直接存入postfix数组
       {
          postfix[j++]=c;
          c=*(infix+i);
          i++;
          if(c<'0'||c>'9') //如果不是数字,则在后面添加空格,以便区分各个符号
            {
            postfix[j++]=' ';
            }
       }
      if(')'==c) //不是数字,则判断是否为右括号。[括号的优先级最高,所以,如果是右括号的话,就得先进行括号里的各种运算]
      {
    	  e=s.top();s.pop();
          while('('!=e) //直到遇到左括号为止
          {
             postfix[j++]=e;
             postfix[j++]=' ';
             e=s.top();s.pop();
          }
      }
      else if('+'==c||'-'==c) //如果是加减号,因为他俩的优先级最低了,所以此时先将栈里的所有符号出栈后(除非遇到左括号),再把此符号入栈
        {
          if(!(s.size())) //如果是空栈,则直接将加减号入栈
          {
              s.push(c);
          }
          else//如果不是空栈,首先将所有优先级大于加减的出栈,然后再把加减号入栈
          {
              do{
                  e=s.top();s.pop();
                  if('('==e)
                  {
                    s.push(e);
                  }
                  else
                  {
                    postfix[j++]=e;
                    postfix[j++]=' ';
                  }
                }while(s.size()&&'('!=e);  //将栈里的所有符号出栈(除非遇到左括号)
              s.push(c); //最后将新来的加减号再入栈
            }
        }
      else if('*'==c||'/'==c||'('==c) //如果是乘除号或左括号,因为他们的优先级高,所以直接入栈。
        {
          s.push(c);
        }
      else if('\n'==c) //判断一下,所有符号是否都已转换完成
        {
          break;
        }
      else //能走到这个else的,都是我不认识的符号了
        {
          // printf("\nError:input error,the character %d cann't recognize!\n",c);
          return -1;
        }
      c=*(infix+i); //取出下一个字符进行转换
      i++;
    }
  while(s.size()) //转换完成后,栈里可能还有没出栈的运算符号
    {
      e=s.top();s.pop();
      postfix[j++]=e;
      postfix[j++]=' ';
    }
  return true;
}

/*
计算后缀表达式的结果
参数:arr使用空格分隔的后缀表达式字符串。例:arr="31 5 + "
result 保存计算完毕后的结果
注:如何利用栈来计算后缀表达式的结果:依次取出后缀表达式中的符号进行比较,如果是数字,则直接入栈;如果是符号,则出栈两次,弹出两个要计算的因数,进行计算,之后再将计算结果入栈。知道后缀表达式中所有符号都已比较完毕。
*/
double Calculate(char *arr)
{
  // printf("%s\n",arr);
  double d,e,f; //d,e 存放两个因数。f存放d,e计算后的结果.
  stack<double> s;
  char *op; //存放后缀表达式中的每个因数或运算符
  char *buf=arr; //声明bufhe saveptr两个变量,是strtok_r函数的需要。
  char *saveptr=NULL;
  while((op=strtok(buf," "))!=NULL) //利用strtok_r函数分隔字符串
    {
      buf=NULL;
      switch(op[0])
      {
        case '+':
            d=s.top();s.pop();
            e=s.top();s.pop();
          f=d+e;
          s.push(f);
          break;
        case '-':
            d=s.top();s.pop();
            e=s.top();s.pop();
          f=e-d;
          s.push(f);
          break;
        case '*':
          d=s.top();s.pop();
          e=s.top();s.pop();
          f=d*e;
          s.push(f);
          break;
        case '/':
          d=s.top();s.pop();
          e=s.top();s.pop();
          f=e/d;
          s.push(f);
          break;
        default:
          d=atof(op); //不是运算符,就肯定是因数了。所以,用atof函数,将字符串转换为double类型
          s.push(d);
          break;
        }
    }
  double result=s.top();s.pop();
  return result;
}


 
 

你可能感兴趣的:(编程,表达式,四则运算)