逆波兰表达式的生成及计算

逆波兰表达式(后缀表达式)生成算法:
(1)构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。

(2)读入一个用中缀表示法表示的简单算术表达式,为方便起见,认为地在字符串后面加入一个特殊字符“;”,并设其优先级为0。

(3)从左至右扫描该算术表达式的每一个字符,如果该字符是数字,则分析到该数字串的结束并将该数字串加入结果字符串,小数点亦算入数字串。

(4)如果该字符是运算符,则按如下操作:

  如果该字符是左括号“(”,则该字符直接压入运算符栈。

  如果该字符是右括号“)”,则把运算符栈顶元素弹出直至第一次遇到左括号。

  如果该字符是算术运算符且其优先关系高于运算符栈顶的运算符,则将该运算符入栈。

  否则,将栈顶的运算符从栈中弹出至结果字符串末尾,直至栈顶运算符的优先级低于当前运算符,并将该字符入栈。

(5)重复上述操作(3)-(4)直至扫描完整个简单算术表达式(遇到特殊字符“;”)。

如:

一般简单表达式:((4+5)*6-5)/2+3*2

逆波兰表达式:4 5 + 6 * 5 - 2 / 3 2 * +

步骤如下:

  运算符栈 结果字符串

第1步: ; ""

第2步: ;( ""

第3步: ;(( ""

第4步: ;(( "4"

第5步: ;((+ "4 5"

第6步: ;( "4 5 +"

第7步: ;(* "4 5 +"

第8步: ;(* "4 5 + 6"

第9步: ;(- "4 5 + 6 *"

第10步: ;(- "4 5 + 6 * 5"

第11步: ; "4 5 + 6 * 5 -"

第12步: ;/ "4 5 + 6 * 5 -"

第13步: ;/ "4 5 + 6 * 5 - 2"

第14步: ;+ "4 5 + 6 * 5 - 2 /"

第15步: ;+ "4 5 + 6 * 5 - 2 / 3"

第16步: ;+* "4 5 + 6 * 5 - 2 / 3"

第17步: ;+* "4 5 + 6 * 5 - 2 / 3 2"

第18步: ;+ "4 5 + 6 * 5 - 2 / 3 2 *"

第19步: ; "4 5 + 6 * 5 - 2 / 3 2 * +"

其中运算符优先级如下:

* / :2

+ - :1

; :0

逆波兰表达式求值算法:

(1)构建一个操作数栈,类型为float;

(2)依次扫描逆波兰表达式的每一项;

(3)如果是数字串则压入操作数栈;

(4)如果是运算符,则从操作数栈顶弹出两个操作数,与运算符进行运算,结果压入操作数栈。

(5)不断重复以上步骤直至扫描完逆波兰表达式。

(6)此时操作数栈必定只剩一个数据,即为逆波兰表达式的值,弹出输出。

如:如上表达式计算结果为:30.5

逆波兰表达式生成及求值的C++实现:

//Stack.h文件:

#ifndef STACK_H

#define STACK_H

template <class>

struct Node

{

  T data;

  Node<t> *next; //此处<t>也可以省略

};

template <class>

class CStack

{

public:

  CStack(); //构造函数,置空链栈

  ~CStack(); //析构函数,释放链栈中各结点的存储空间

  void Push(T x); //将元素x入栈

  T Pop(); //将栈顶元素出栈

  T GetTop(); //取栈顶元素(并不删除)

  bool Empty(); //判断链栈是否为空栈

private:

  Node<t> *top; //栈顶指针即链栈的头指针

};

#endif

//Stack.cpp文件:

#include "Stack.h"

/*

* 前置条件:栈不存在

* 输 入:无

* 功 能:栈的初始化

* 输 出:无

* 后置条件:构造一个空栈

*/

template <class>

CStack<t>::CStack()

{

top=NULL; 

}

/*

* 前置条件:栈已存在

* 输 入:无

* 功 能:销毁栈

* 输 出:无

* 后置条件:释放栈所占用的存储空间

*/

template <class>

CStack<t>::~CStack()

{

while (top)

{

  Node<t> *p;

  p=top-&gt;next;

  delete top;

  top=p;

}

}

/*

* 前置条件:栈已存在

* 输 入:节点s

* 功 能:在栈顶插入该节点

* 输 出:无

* 后置条件:如果插入成功,栈顶增加了一个元素

*/

template<class> 

void CStack<t>::Push(T x)

{

  Node<t> *s;

s=new Node<t>;  

  s-&gt;data = x; //申请一个数据域为x的结点s

  s-&gt;next = top; 

top=s; //将结点s插在栈顶

}

/*

* 前置条件:栈已存在

* 输 入:无

* 功 能:删除栈顶元素

* 输 出:如果删除成功,返回被删元素值,否则,抛出异常

* 后置条件:如果删除成功,栈顶减少了一个元素

*/  

template <class> 

T CStack<t>::Pop()

{  

  Node<t> *p;

T x; 

  if (top==NULL) throw "下溢";

  x=top-&gt;data; //暂存栈顶元素

  p=top; 

top=top-&gt;next; //将栈顶结点摘链

  delete p;

  return x;

}

/*

* 前置条件:栈已存在

* 输 入:无

* 功 能:读取当前的栈顶元素

* 输 出:若栈不空,返回当前的栈顶元素值

* 后置条件:栈不变

*/

template <class> 

T CStack<t>::GetTop()

{

  if (top!=NULL) 

  return top-&gt;data;

}

/*

* 前置条件:栈已存在

* 输 入:无

* 功 能:判断栈是否为空

* 输 出:如果栈为空,返回1,否则,返回0

* 后置条件:栈不变

*/

template <class> 

bool CStack<t>::Empty()

{

  if(top==NULL) 

  return 1;

else 

  return 0;

}

//Rpnexp.h文件

#ifndef Rpnexp_H

#define Rpnexp_H

#include<string>

#include<vector>

using namespace std;

class CRpnexp

{

public:

CRpnexp(string str);

~CRpnexp();

void Resetexp(string str);

void Printexp();

void Convertexp();

void Calcrpn();

private:

bool Isdigit(char ch);

void Breakupstr(vector<string> &vec,string str);

int Prior(char ch);

float Tofloat(string str);

float Midcalc(float num1,float num2,char oper);

string origexp;

string rpnexp;

};

#endif

//Rpnexp.cpp文件:

#include "Rpnexp.h"

#include "Stack.cpp"

#include<iostream>

using namespace std;

CRpnexp::CRpnexp(string str)

{

origexp=str;

origexp+=';';

}

CRpnexp::~CRpnexp()

{

}

void CRpnexp::Calcrpn()

{

vector<string> vec;

int i;

string tmp;

for(i=0;i&lt;rpnexp.length();i++)

{

  tmp.erase();

  if(rpnexp[i]!=' '&&lt;rpnexp.length())

  {

  while(rpnexp[i]!=' ')

  tmp+=rpnexp[i++];

  vec.push_back(tmp);

  }

}

CStack<float> rslt;

for(i=0;i&lt;vec.size();i++)

{

  if(Isdigit(vec[i][0])||(!Isdigit(vec[i][0])&&Isdigit(vec[i][1])))

  rslt.Push(Tofloat(vec[i]));

  else

  {

  rslt.Push(Midcalc(rslt.Pop(),rslt.Pop(),vec[i][0]));

  }

}

cout&lt;&lt;rslt.Pop()&lt;&lt;endl;

}

void CRpnexp::Convertexp()

{

vector<string> vectmp;

Breakupstr(vectmp,origexp);

CStack<char> operstack;

operstack.Push(';');

int i;

for(i=0;i&lt;vectmp.size();i++)

{

  if(Isdigit(vectmp[i][0])||(!Isdigit(vectmp[i][0])&&Isdigit(vectmp[i][1])))

  {

  rpnexp+=vectmp[i];

  rpnexp+=' ';

  }

  else if(vectmp[i][0]=='(')

  operstack.Push(vectmp[i][0]);

  else if(vectmp[i][0]==')')

  {

  while(operstack.GetTop()!='(')

  {

  rpnexp+=operstack.Pop();

  rpnexp+=' ';

  }

  operstack.Pop();

  }

  else if(Prior(vectmp[i][0])&lt;=Prior(operstack.GetTop()))

  {

  rpnexp+=operstack.Pop();

  rpnexp+=' ';

  while(operstack.GetTop()!=';'&&Prior(vectmp[i][0])&lt;=Prior(operstack.GetTop()))

  {

  rpnexp+=operstack.Pop();

  rpnexp+=' ';

  }

  if(vectmp[i][0]!=';')

  operstack.Push(vectmp[i][0]);

  }

  else

  operstack.Push(vectmp[i][0]);

}

while(operstack.GetTop()!=';')

{

  rpnexp+=operstack.Pop();

  rpnexp+=' ';

}

}

void CRpnexp::Printexp()

{

cout&lt;&lt;rpnexp&lt;&lt;endl;

int i;

}

void CRpnexp::Resetexp(string str)

{

origexp=str;

origexp+=';';

}

void CRpnexp::Breakupstr(vector<string> &vec,string str)

{

string tmp;

int i;

for(i=0;i&lt;str.length();i++)

{

  if(str[i]==' ')

  continue;

  tmp="";

  if(str[i]=='-' || str[i]=='+')

  {

  if(i==0 || str[i-1]=='(' || (!Isdigit(str[i-1]) && str[i-1]!=')') )

  tmp+=str[i++];

  }

  if(Isdigit(str[i]) || str[i]=='.')

  {

  while(Isdigit(str[i]) || str[i]=='.')

  tmp+=str[i++];

  vec.push_back(tmp);

  tmp="";

  }

  if(!Isdigit(str[i]) && str[i]!='.')

  vec.push_back(str[i]+tmp);

}

}

bool CRpnexp::Isdigit(char ch)

{

if(ch&gt;='0'&&lt;='9')

  return true;

return false;

}

int CRpnexp::Prior(char ch)

{

switch(ch)

{

case ';':

  return 0;

case '+':

  return 3;

case '-':

  return 3;

case '*':

  return 4;

case '/':

  return 4;

default:

  return -1;

}

}

float CRpnexp::Tofloat(string str)

{

int i,zs=0,j=0;

if(str[0]=='-'||str[0]=='+')

{

  j=1;

}

for(i=j;i&lt;str.length();i++)

{

  if(str[i]=='.')

  break;

  zs+=str[i]-'0';

  zs*=10;

}

zs/=10;

int xs=0;

for(i++;i&lt;str.length();i++)

{

  xs+=str[i]-'0';

  xs/=10;

}

xs*=10;

if(str[0]=='-')

  return 0-(zs+xs);

return zs+xs;

}

float CRpnexp::Midcalc(float num1,float num2,char oper)

{

switch(oper)

{

case '+':

  return num1+num2;

case '-':

  return num1-num2;

case '*':

  return num1*num2;

case '/':

  if(num2==0)

  throw "表达式错误,除数不能为零!";

  return num1/num2;

default:

  throw "运算符错误!";

}

}

//Main.cpp文件:

#include"Rpnexp.h"

#include"DbStack.cpp"

#include<string>

#include<iostream>

using namespace std;

int main()

{

char ch='Y';

while((ch & 0xDF)=='Y')

{

  cout&lt;&lt;"请输入一般表达式,中间不要留空,可用的算术运算符是“+,-,*,/”:"&lt;&lt;endl;

  string expression;

  cin&gt;&gt;expression;

  CRpnexp exp(expression);

  exp.Convertexp();

  cout&lt;&lt;"逆波兰表达式是:";

  exp.Printexp();

  cout&lt;&lt;"表达式的值是:";

  exp.Calcrpn();

  cout&lt;&lt;"是否继续?Y/N:";

  cin&gt;&gt;ch;

}

return 0;

}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
逆波兰式也称为后缀表达式,是一种不含括号的数学表达式。其计算顺序与中缀表达式相同,但是可以通过栈来实现计算。 下面是用 C++ 实现逆波兰式生成计算的示例代码: ```c++ #include <iostream> #include <stack> #include <string> #include <vector> using namespace std; int main() { // 输入逆波兰式 string rpn; cout << "请输入逆波兰式:" << endl; getline(cin, rpn); // 将逆波兰式拆分为操作数和操作符 vector<string> tokens; string token = ""; for (int i = 0; i < rpn.length(); i++) { if (rpn[i] == ' ') { tokens.push_back(token); token = ""; } else { token += rpn[i]; } } tokens.push_back(token); // 计算逆波兰式 stack<int> numStack; for (int i = 0; i < tokens.size(); i++) { string token = tokens[i]; if (token == "+" || token == "-" || token == "*" || token == "/") { int num2 = numStack.top(); numStack.pop(); int num1 = numStack.top(); numStack.pop(); int result; if (token == "+") { result = num1 + num2; } else if (token == "-") { result = num1 - num2; } else if (token == "*") { result = num1 * num2; } else if (token == "/") { result = num1 / num2; } numStack.push(result); } else { int num = stoi(token); numStack.push(num); } } // 输出结果 cout << "计算结果:" << numStack.top() << endl; return 0; } ``` 这个程序首先要求用户输入一个逆波兰式,然后将其拆分为操作数和操作符。接着,程序使用一个栈来计算逆波兰式的值。对于每个操作符,程序将栈顶的两个数弹出,计算后将结果压回栈中。对于每个操作数,程序将其转换为整数并压入栈中。最后,程序输出计算结果。 注意,这个程序没有对输入的逆波兰式进行任何错误检查,如果输入的逆波兰式不符合规范,程序可能会出错。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值