栈的应用 - 波兰式与逆波兰式的计算

   在栈的实现 - C++中,简要介绍了栈的相关特性,及其C++的实现。在栈的应用 - 波兰式与逆波兰式中,借助于栈,实现了中缀表达式到前缀表达式和后缀表达式的转换。

   正如已经提到的,因为此前在实现栈的时候,栈的元素类型elementType是通过typedef来指定的,这样虽然也可以根据需要实例化不同类型的栈,但是在一个应用中,只能指定一种元素类型,其使用也就受到了一定的限制。也正是由于这个限制,我没有同时给出波兰式和逆波兰式的计算,因为转换过程中,栈的元素类型是char,而在计算的过程中,栈的元素类型是int。当然,我们可以再定义一个类,但是这样真的太麻烦,而且很不优雅,在C++中有一个很好的工具——模板,它可以非常完美地解决我的问题,下面的代码中,对栈的实现做了略微的修改,并且将波兰式与逆波兰式的计算也补齐了。

   波兰式与逆波兰式的计算规则在栈的应用 - 波兰式与逆波兰式中已经说明了,在此不做赘述,不过值得注意的点还是要再强调一下,给自己也提个醒吧。在计算时,操作数的顺序要格外注意,否则遇到减法或除法就可能会产生错误的结果。

  • 计算前缀表达式(波兰式)时,从右至左扫描表达式 ,出栈时,先弹出的为操作数1(op1),后弹出的为操作数2(op2)
  • 计算后缀表达式(逆波兰式)时,从左至右扫描表达式,出栈时,先弹出的为操作数2(op2),后弹出的为操作数1(op1)
  • 对于除法,要检测除数(op2)是否为0

   实现代码
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;
}


   运行结果
栈的应用 - 波兰式与逆波兰式的计算_第1张图片


   小贴士
   使用模板类可以为实际应用带来极大的便利。模板类的定义方式如下:

template <class elementType>
class MyStack {
....
};

   其中elementType在例化对象时会自动转化为指定的类型。

   模板类的成员函数要么就直接在类体中实现,要么就和模板类在同一文件中实现,否则编译将出错。这也是为什么,现在没有的MyStack.cpp,因为MyStack类的所有成员函数都在MyStack.h中实现了。在模板类的类体外实现成员函数的形式如下:

template 
bool MyStack::push(elementType e) {
...
}

   实例化模板类的对象时,需要指定具体的类型:

Mystack<int> calcStack(length, 0);

你可能感兴趣的:(笔记摘抄)