上一篇笔记中,简单讲到了栈的特性,并且给出了栈的实现,现在要利用栈来实现表达式的求值问题。
有三个名词与表达式的计算密切相关,分别是中缀表达式、前缀表达式和后缀表达式,它们都是表达式的一种记法,区别是运算符相对于操作数的位置不同:前缀表达式的操作符位于与其相关的操作数之前;中缀表达式的操作符位于与其相关的操作数之间;后缀表达式的操作符位于与其相关的操作数之后。(简而言之,前、中、后就是指操作符所在的位置)
举例:
1+((2+3)*4)-5
-+1*+2345
123+4*+5-
可以看到,中缀表达式其实就是人们常用的算术表达式的表示方法,为了正确表示运算顺序,可能会需要借用括号,人看起来清晰易懂,但是对于计算机来说,计算中缀表达式却是很复杂的。前缀表达式和后缀表达式则是计算机更易理解和计算的表示方法,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀表达式或者后缀表达式,然后再进行求值。
前缀表达式,又称波兰式,计算机计算前缀表达式的值时,需要借助一个栈,从右至左扫描表达式,遇到操作数时,直接将操作数入栈;遇到操作符时,从栈中弹出两个操作数,进行运算,然后将运算结果压入栈中;重复上述过程,直至扫描到表达式的最左端,最后运算得出的值即为所求表达式的值。
后缀表达式,又称逆波兰式,计算机计算后缀表达式时,也需要借助一个栈,计算过程与前缀表达式类似,只是扫描表达式的顺序是从左至右。扫描过程中,遇到操作数,则将操作数直接压入栈中;遇到操作符时,从栈中弹出两个操作数,进行运算,然后将运算结果压入栈中;重复上述结果,直至扫描到表达式的最右端,最后运算得出的值即为所求表达式的值。
注意:在进行运算时,操作数的顺序不能乱,不然对于除法或减法可能产生错误的结果。
将中缀表达式转换为后缀表达式遵循以下步骤:
将中缀表达式转换为前缀表达式遵循以下步骤:
以下给出利用栈实现中缀表达式转换为后缀表达式和前缀表达式的实现代码。(本来想把后缀表达式和前缀表达式的计算一起实现,但是由于栈的元素类型需要做一些修改,后续会补上。)
代码中MyStack.h
和MyStack.cpp
是栈的实现代码,与前一篇笔记一样;Expression.h
和Expression.cpp
则给出了具体的转换函数toReversePolishNotation()
和toPolishNotation()
;test.cpp
通过两个表达式,对函数进行了测试验证。
MyStack.h
#ifndef _MYSTACK_H_
#define _MYSTACK_H_
#include
#include
#include
#include
using namespace std;
#define INISIZE 2
#define INIINCREMENT 2
#define DYNAMIC
typedef char elementType;
class MyStack {
public:
int top;
int size;
int increment;
elementType * data;
MyStack(int size = INISIZE, int increment = INIINCREMENT);
~MyStack();
bool pop(elementType & e);
bool push(elementType e);
bool isEmpty();
bool isFull();
bool getTopElement(elementType & e);
void printStack(); //打印栈中所有的元素,主要用于调试
};
#endif
MyStack.cpp
#include "MyStack.h"
MyStack::MyStack(int size, int increment)
{
top = -1;
this->size = size;
this->increment = increment;
data = (elementType *)malloc(sizeof(elementType) * this->size);
}
MyStack::~MyStack()
{
if (data) {
free(data);
}
}
bool MyStack::pop(elementType & e)
{
if (isEmpty()) {
e = -1;
return false;
} else {
e = data[top];
top --;
return true;
}
}
bool MyStack::push(elementType e)
{
if (isFull()) {
#ifdef DYNAMIC
size = size + increment;
data = (elementType *)realloc(data, sizeof(elementType) * this->size);
if (data == NULL) {
return false;
}
top ++;
data[top] = e;
return true;
#else
return false;
#endif
} else {
top ++;
data[top] = e;
return true;
}
}
bool MyStack::isEmpty()
{
return top == -1;
}
bool MyStack::isFull()
{
return top == size - 1;
}
bool MyStack::getTopElement(elementType &e)
{
if (isEmpty()) {
e = -1;
return false;
} else {
e = data[top];
return true;
}
}
void MyStack::printStack()
{
int i;
cout << "SN\t\telement" << endl;
for (i=0;i<=top;i++) {
cout << i << "\t\t" << data[i] << endl;
}
cout << "total elements : " << top+1 << endl;
cout << "stack size : " << size << endl;
}
Expression.h
#ifndef _EXPRESSION_H_
#define _EXPRESSION_H_
#include "MyStack.h"
#include
#include
/*
* toPolishNotation: 将中缀表达式转换为前缀表达式
* toReversePolishNotation: 将中缀表达式转换为后缀表达式
*/
char * toPolishNotation(const char* express);
char * toReversePolishNotation(const char* express);
#endif
Expression.cpp
#include "Expression.h"
/*
* 判断字符op是否是运算符
*/
bool isOperator(char op)
{
return (op=='+')||(op=='-')||(op=='*')||(op=='/');
}
/*
* 获取运算符的优先级
* +或- : 2
* *或/ : 3
* 其它 : 1
*/
int getPriority(char op)
{
switch(op) {
case '+':
case '-':
return 2;
case '*':
case '/':
return 3;
default :
return 1;
}
}
/*
* 反转一个字符串,在转换为后缀表达式时用到
*/
void reverseStr(char *str)
{
int i=0;
int j=strlen(str)-1;
char temp;
while(i*/
char * toReversePolishNotation(const char * expression)
{
if (expression == NULL) {
return NULL;
}
int length = strlen(expression);
MyStack opStack(length,0);
MyStack tempStack(length,0);
char * result = (char *)malloc(sizeof(char) * (length+1));
const char * pstr = expression;
char e,topE;
int i=0;
while(*pstr) {
if (isdigit(*pstr)) {
tempStack.push(*pstr);
} else if (isOperator(*pstr)) {
while (opStack.getTopElement(topE)) {
if ((topE=='(') || (getPriority(*pstr)>getPriority(topE)))
break;
opStack.pop(e);
tempStack.push(e);
}
opStack.push(*pstr);
} else if (*pstr == '(') {
opStack.push(*pstr);
} else if (*pstr == ')') {
while (opStack.pop(e)) {
if (e == '(')
break;
tempStack.push(e);
}
}
pstr ++;
}
while (opStack.pop(e)) {
tempStack.push(e);
}
while (tempStack.pop(e)) {
result[i] = e;
i ++;
}
result[i] = '\0';
reverseStr(result);
return result;
}
/*
* 函数功能: 将中缀表达式转换为前缀表达式
* 参数: expression: 待转换的中缀表达式
* 返回值: 已经转换好的前缀表达式
*/
char * toPolishNotation(const char * expression)
{
if (expression == NULL)
return NULL;
int length = strlen(expression);
MyStack opStack(length,0);
MyStack tempStack(length,0);
char * result = (char *)malloc((length+1) * sizeof(char));
char e,topE;
int i=0;
int index = length - 1;
while (index >= 0) {
if (isdigit(expression[index])) {
tempStack.push(expression[index]);
} else if (isOperator(expression[index])) {
while (opStack.getTopElement(topE)) {
if ((topE==')') || (getPriority(expression[index])>=getPriority(topE)))
break;
opStack.pop(e);
tempStack.push(e);
}
opStack.push(expression[index]);
} else if (expression[index] == ')') {
opStack.push(expression[index]);
} else if (expression[index] == '(') {
while (opStack.pop(e)) {
if (e == ')')
break;
tempStack.push(e);
}
}
index --;
}
while (opStack.pop(e)) {
tempStack.push(e);
}
while (tempStack.pop(e)) {
result[i] = e;
i ++;
}
result[i] = '\0';
return result;
}
test.cpp
#include "Expression.h"
int main()
{
char expression[] = "1+((2+3)*4)-5";
char ex[] = "1+2*5";
char *result = toPolishNotation(expression);
cout << "expression : " << expression << endl;
cout << "Polish Notation : " << result << endl;
result = toReversePolishNotation(expression);
cout << "Reverse Polish Notation : " << result << endl;
cout << endl;
result = toPolishNotation(ex);
cout << "expression : " << ex << endl;
cout << "Polish Notation : " << result << endl;
result = toReversePolishNotation(ex);
cout << "Reverse Polish Notation : " << result << endl;
cout << endl;
return 0;
}