在栈的实现 - C++中,简要介绍了栈的相关特性,及其C++的实现。在栈的应用 - 波兰式与逆波兰式中,借助于栈,实现了中缀表达式到前缀表达式和后缀表达式的转换。
正如已经提到的,因为此前在实现栈的时候,栈的元素类型elementType是通过typedef来指定的,这样虽然也可以根据需要实例化不同类型的栈,但是在一个应用中,只能指定一种元素类型,其使用也就受到了一定的限制。也正是由于这个限制,我没有同时给出波兰式和逆波兰式的计算,因为转换过程中,栈的元素类型是char,而在计算的过程中,栈的元素类型是int。当然,我们可以再定义一个类,但是这样真的太麻烦,而且很不优雅,在C++中有一个很好的工具——模板,它可以非常完美地解决我的问题,下面的代码中,对栈的实现做了略微的修改,并且将波兰式与逆波兰式的计算也补齐了。
波兰式与逆波兰式的计算规则在栈的应用 - 波兰式与逆波兰式中已经说明了,在此不做赘述,不过值得注意的点还是要再强调一下,给自己也提个醒吧。在计算时,操作数的顺序要格外注意,否则遇到减法或除法就可能会产生错误的结果。
实现代码
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;
template <class 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(); //打印栈中所有的元素,主要用于调试
};
template <class elementType>
MyStack::MyStack(int size, int increment)
{
top = -1;
this->size = size;
this->increment = increment;
data = (elementType *)malloc(sizeof(elementType) * this->size);
}
template <class elementType>
MyStack::~MyStack()
{
if (data) {
free(data);
}
}
template <class elementType>
bool MyStack::pop(elementType & e)
{
if (isEmpty()) {
e = -1;
return false;
} else {
e = data[top];
top --;
return true;
}
}
template <class elementType>
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;
}
}
template <class elementType>
bool MyStack::isEmpty()
{
return top == -1;
}
template <class elementType>
bool MyStack::isFull()
{
return top == size - 1;
}
template <class elementType>
bool MyStack::getTopElement(elementType &e)
{
if (isEmpty()) {
e = -1;
return false;
} else {
e = data[top];
return true;
}
}
template <class elementType>
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;
}
#endif
Expression.h
#ifndef _EXPRESSION_H_
#define _EXPRESSION_H_
#include "MyStack.h"
#include
#include
#define OK 0x01
#define ERROR 0x01<<1
/*
* toPolishNotation: 将中缀表达式转换为前缀表达式
* toReversePolishNotation: 将中缀表达式转换为后缀表达式
* calcPolishNotation : 计算前缀表达式的值
* calcRePolishNotation : 计算后缀表达式的值
*/
char * toPolishNotation(const char* express);
char * toReversePolishNotation(const char* express);
int calcPolishNotation(const char* polishNotation, int &status);
int calcRePolishNotation(const char* rePolishNotation, int &status);
#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);
}
} else {
return NULL;
}
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);
}
} else {
return NULL;
}
index --;
}
while (opStack.pop(e)) {
tempStack.push(e);
}
while (tempStack.pop(e)) {
result[i] = e;
i ++;
}
result[i] = '\0';
return result;
}
bool calc(int& op1, int op2, char op)
{
switch(op) {
case '+':
op1+=op2;
return true;
case '-':
op1-=op2;
return true;
case '*':
op1*=op2;
return true;
case '/':
if (op2==0) {
return false;
}
op1/=op2;
return true;
default:
return false;
}
}
int calcPolishNotation(const char * polishNotation, int &status)
{
int index;
int op1,op2;
int length = strlen(polishNotation);
MyStack<int> calcStack(length,0);
if(polishNotation == NULL) {
status = ERROR;
return -1;
}
index =length -1;
while(index >= 0) {
if (isdigit(polishNotation[index])) {
calcStack.push(polishNotation[index]-'0');
} else {
if(!calcStack.pop(op1)) {
status = ERROR;
return -1;
}
if(!calcStack.pop(op2)) {
status = ERROR;
return -1;
}
if (!calc(op1,op2,polishNotation[index])) {
status = ERROR;
return -1;
}
calcStack.push(op1);
}
index --;
}
if(!calcStack.pop(op1)) {
status = ERROR;
return -1;
}
if(calcStack.isEmpty()) {
status = OK;
return op1;
}
status = ERROR;
return -1;
}
int calcRePolishNotation(const char * rePolishNotation, int &status)
{
int index=0;
int op1,op2;
int length = strlen(rePolishNotation);
MyStack<int> calcStack(length,0);
if (rePolishNotation == NULL) {
status = ERROR;
return -1;
}
while(index<length) {
if (isdigit(rePolishNotation[index])) {
calcStack.push(rePolishNotation[index]-'0');
} else {
if (!calcStack.pop(op2)) {
status = ERROR;
return -1;
}
if (!calcStack.pop(op1)) {
status = ERROR;
return -1;
}
if (!calc(op1,op2,rePolishNotation[index])) {
status = ERROR;
return -1;
}
calcStack.push(op1);
}
index ++;
}
if (!calcStack.pop(op1)) {
status = ERROR;
return -1;
}
if (calcStack.isEmpty()) {
status = OK;
return op1;
}
status = ERROR;
return -1;
}
test.cpp
#include "Expression.h"
int main()
{
int op,status;
char expression[] = "1+((2+3)*4)-5";
char ex[] = "2*(5-2)*4/3";
char *result = toPolishNotation(expression);
cout << "expression : " << expression << endl;
cout << "Polish Notation : " << result << endl;
op = calcPolishNotation(result,status);
if(status == OK) {
cout << op << endl;
} else {
cout << "polish ERROR!" << endl;
}
result = toReversePolishNotation(expression);
cout << "Reverse Polish Notation : " << result << endl;
op = calcRePolishNotation(result,status);
if (status == OK) {
cout << op << endl;
} else {
cout << "ERROR!" << endl;
}
cout << endl;
result = toPolishNotation(ex);
cout << "expression : " << ex << endl;
cout << "Polish Notation : " << result << endl;
op = calcPolishNotation(result,status);
if(status == OK) {
cout << op << endl;
} else {
cout << "Polish ERROR!" << endl;
}
result = toReversePolishNotation(ex);
cout << "Reverse Polish Notation : " << result << endl;
op = calcRePolishNotation(result,status);
if (status == OK) {
cout << op << endl;
} else {
cout << "ERROR!" << endl;
}
cout << endl;
return 0;
}
小贴士
使用模板类可以为实际应用带来极大的便利。模板类的定义方式如下:
template <class elementType>
class MyStack {
....
};
其中elementType在例化对象时会自动转化为指定的类型。
模板类的成员函数要么就直接在类体中实现,要么就和模板类在同一文件中实现,否则编译将出错。这也是为什么,现在没有的MyStack.cpp,因为MyStack类的所有成员函数都在MyStack.h中实现了。在模板类的类体外实现成员函数的形式如下:
template
bool MyStack::push(elementType e) {
...
}
实例化模板类的对象时,需要指定具体的类型:
Mystack<int> calcStack(length, 0);