逆波兰表达式(后缀表达式)生成算法:
(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->next;
delete top;
top=p;
}
}
/*
* 前置条件:栈已存在
* 输 入:节点s
* 功 能:在栈顶插入该节点
* 输 出:无
* 后置条件:如果插入成功,栈顶增加了一个元素
*/
template<class>
void CStack<t>::Push(T x)
{
Node<t> *s;
s=new Node<t>;
s->data = x; //申请一个数据域为x的结点s
s->next = top;
top=s; //将结点s插在栈顶
}
/*
* 前置条件:栈已存在
* 输 入:无
* 功 能:删除栈顶元素
* 输 出:如果删除成功,返回被删元素值,否则,抛出异常
* 后置条件:如果删除成功,栈顶减少了一个元素
*/
template <class>
T CStack<t>::Pop()
{
Node<t> *p;
T x;
if (top==NULL) throw "下溢";
x=top->data; //暂存栈顶元素
p=top;
top=top->next; //将栈顶结点摘链
delete p;
return x;
}
/*
* 前置条件:栈已存在
* 输 入:无
* 功 能:读取当前的栈顶元素
* 输 出:若栈不空,返回当前的栈顶元素值
* 后置条件:栈不变
*/
template <class>
T CStack<t>::GetTop()
{
if (top!=NULL)
return top->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<rpnexp.length();i++)
{
tmp.erase();
if(rpnexp[i]!=' '&<rpnexp.length())
{
while(rpnexp[i]!=' ')
tmp+=rpnexp[i++];
vec.push_back(tmp);
}
}
CStack<float> rslt;
for(i=0;i<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<<rslt.Pop()<<endl;
}
void CRpnexp::Convertexp()
{
vector<string> vectmp;
Breakupstr(vectmp,origexp);
CStack<char> operstack;
operstack.Push(';');
int i;
for(i=0;i<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])<=Prior(operstack.GetTop()))
{
rpnexp+=operstack.Pop();
rpnexp+=' ';
while(operstack.GetTop()!=';'&&Prior(vectmp[i][0])<=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<<rpnexp<<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<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>='0'&<='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<str.length();i++)
{
if(str[i]=='.')
break;
zs+=str[i]-'0';
zs*=10;
}
zs/=10;
int xs=0;
for(i++;i<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<<"请输入一般表达式,中间不要留空,可用的算术运算符是“+,-,*,/”:"<<endl;
string expression;
cin>>expression;
CRpnexp exp(expression);
exp.Convertexp();
cout<<"逆波兰表达式是:";
exp.Printexp();
cout<<"表达式的值是:";
exp.Calcrpn();
cout<<"是否继续?Y/N:";
cin>>ch;
}
return 0;
}
(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->next;
delete top;
top=p;
}
}
/*
* 前置条件:栈已存在
* 输 入:节点s
* 功 能:在栈顶插入该节点
* 输 出:无
* 后置条件:如果插入成功,栈顶增加了一个元素
*/
template<class>
void CStack<t>::Push(T x)
{
Node<t> *s;
s=new Node<t>;
s->data = x; //申请一个数据域为x的结点s
s->next = top;
top=s; //将结点s插在栈顶
}
/*
* 前置条件:栈已存在
* 输 入:无
* 功 能:删除栈顶元素
* 输 出:如果删除成功,返回被删元素值,否则,抛出异常
* 后置条件:如果删除成功,栈顶减少了一个元素
*/
template <class>
T CStack<t>::Pop()
{
Node<t> *p;
T x;
if (top==NULL) throw "下溢";
x=top->data; //暂存栈顶元素
p=top;
top=top->next; //将栈顶结点摘链
delete p;
return x;
}
/*
* 前置条件:栈已存在
* 输 入:无
* 功 能:读取当前的栈顶元素
* 输 出:若栈不空,返回当前的栈顶元素值
* 后置条件:栈不变
*/
template <class>
T CStack<t>::GetTop()
{
if (top!=NULL)
return top->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<rpnexp.length();i++)
{
tmp.erase();
if(rpnexp[i]!=' '&<rpnexp.length())
{
while(rpnexp[i]!=' ')
tmp+=rpnexp[i++];
vec.push_back(tmp);
}
}
CStack<float> rslt;
for(i=0;i<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<<rslt.Pop()<<endl;
}
void CRpnexp::Convertexp()
{
vector<string> vectmp;
Breakupstr(vectmp,origexp);
CStack<char> operstack;
operstack.Push(';');
int i;
for(i=0;i<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])<=Prior(operstack.GetTop()))
{
rpnexp+=operstack.Pop();
rpnexp+=' ';
while(operstack.GetTop()!=';'&&Prior(vectmp[i][0])<=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<<rpnexp<<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<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>='0'&<='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<str.length();i++)
{
if(str[i]=='.')
break;
zs+=str[i]-'0';
zs*=10;
}
zs/=10;
int xs=0;
for(i++;i<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<<"请输入一般表达式,中间不要留空,可用的算术运算符是“+,-,*,/”:"<<endl;
string expression;
cin>>expression;
CRpnexp exp(expression);
exp.Convertexp();
cout<<"逆波兰表达式是:";
exp.Printexp();
cout<<"表达式的值是:";
exp.Calcrpn();
cout<<"是否继续?Y/N:";
cin>>ch;
}
return 0;
}