栈和二叉树的使用--四则运算

                   使用栈来检测表达式括号的匹配,使用二叉树来保存运算的中缀表达式,对表达式树进行后序遍历得到后缀表达式,运算得到表达式的值。

                   检测配对使用栈保存‘(’符号,当遇到一个‘)’,出栈,若栈空则出错,表达式结束,栈非空也出错。

                  

                   3*5+2构造二叉树如下

                  


                    四则运算有优先级和结合关系,在构造二叉树时影响构造的过程。优先级高的运算符深度较深,在后序遍历时,先遍历到。

                    2+3*5构造二叉树如下

    


          遇到括号,将括号中的看成一个子运算式,使用递归来解决。

         在中缀表达式转换事的算法描述如下:

         当当前的符号是运算数时,检测当前是否有树根,没有则作为树根,否则作为前一个运算符的右孩子,当根节点没有右孩子则作为右孩子,有右孩子则作为右孩子的右元算数。如果是+或-,那它就是已知的最后一个运算符,将它作为根节点,原来的树作为左子树。如果是*或/,优先级高,就要和根节点做比较,怎么改变。如根节点是+或-,则则应该先运算,所以作为右子树的根节点,原来的子树作为它的左子树。如果是同优先级的,原来的先计算,当前最为根节点,原来作为左子树。

        

#ifndef EXCEPTIONS_H
#define EXCEPTIONS_H

#include <exception>
#include <iostream>

/**
 * @brief The OutOfBoundary class 越界异常
 */
class OutOfBoundary : public std::exception
{
    friend std::ostream& operator << (std::ostream& os, const std::exception &obj) {
        os << obj.what();
        return os;
    }

public:
    OutOfBoundary() throw(): exception(){}
    ~OutOfBoundary() throw(){}

    const char* what() const throw(){
        return "out of boundary!";
    }

};
/**
 * @brief The BadValue class 坏值异常
 */
class BadValue : public std::exception
{
    friend std::ostream& operator << (std::ostream& os, const BadValue &obj) {
        os << obj.what();
        return os;
    }
public:
    BadValue() throw(): exception(){}
    ~BadValue() throw(){}
    const char* what() const throw(){
        return "bad value!";
    }

};

class MyException : public std::exception
{
public:
    MyException(const char *_mes) throw() : exception(),info(_mes) {}
    ~MyException() throw(){}
    const char * what() const throw() {
        return info.data();
    }

private:
    std::string info;

};




#endif


#ifndef BALANCE_HPP
#define BALANCE_HPP

#include "linkStack.hpp"

class Balance
{
public:
    enum elemType{OPAREN,CPAREN,OTHER,EOL};
    Balance(const char* ex);
    ~Balance(){}
    bool balance();
private:
    LinkStack<char> _stack;
    const char * _ex;
    elemType getToken();
};

inline
Balance::Balance(const char *ex) : _ex(ex)
{

}

bool Balance::balance()
{
    elemType t = getToken();
    while (t != EOL) {
        switch (t) {
        case OPAREN:
            _stack.push('(');
            break;
        case CPAREN:
            if (_stack.isEmpty()) {
                return false;
            } else {
                _stack.pop();
            }
            break;
        default:
            break;
        }
        t = getToken();
    }

    return _stack.isEmpty(); \
}

Balance::elemType Balance::getToken()
{
    elemType re;

    while(*_ex == ' ') ++_ex;

    if (*_ex >= '0' && *_ex <= '9') {
        while(*_ex >= '0' && *_ex <= '9') {
            ++_ex;
        }
        return OTHER;
    }

    switch (*_ex++) {
    case '(':
        re = OPAREN;
        break;
    case ')':
        re = CPAREN;
        break;
    case '\0':
        re = EOL;
        break;
    default:
        re = OTHER;
        break;
    }
    return re;
}

#endif // BALANCE_HPP


#ifndef CALCULATOR_HPP
#define CALCULATOR_HPP

#include "balance.hpp"
#include "exceptions.hpp"

template <typename T>
class Calculator
{
public:
    /**
     * @brief The elemType enum
     * 数字 加 减 乘 除 开括号open  闭括号close 结束标识
     */
    enum elemType{DATA, ADD, SUB, MULIT, DIV, OPAREN, CPAREN, EOL};
    Calculator(char *ex);
    ~Calculator() {
        destroy(root);
    }
    T result();
private:
    struct node {
        elemType type;
        T data;
        node *lc, *rc;
        node(elemType _type, T _data, node *_lc = 0, node *_rc = 0):
            type(_type),
            data(_data),
            lc(_lc),
            rc(_rc) {

        }
    };

    node *create(char *&ex);
    elemType getToken(char *&ex, T &value);
    void destroy(node *r);
    T result(node *r);

    node *root;
};

template <typename T>
Calculator<T>::Calculator(char *ex)
{
    Balance b(ex);
    if (!b.balance()) {
        throw MyException("() not match!!!");
    }
    root = create(ex);
}

template <typename T>
void Calculator<T>::destroy(node *r)
{
    if (r != NULL) {
        destroy(r->lc);
        destroy(r->rc);
        delete r;
    }
}
template <typename T>
typename Calculator<T>::node* Calculator<T>::create(char *&ex)
{
    node* p, *root = 0;
    elemType reType;
    T value;
    while(*ex) {
        reType = getToken(ex,value);
        switch (reType) {
        case DATA:
        case OPAREN:
            if(reType == DATA) {
                p = new node(DATA,value);
            } else {
                /**
                  解决这样情况
                  (4-2)*5
                  树形结构为

                    |------|                         |------|
                    | _ |        *                 | _ |
                    |------|    --------------->          |------|     (X)
                     |    \                        |    \
                     |     \                       |     \
                  |------|    |-----|                   |------|    |-----|
                  | 4 |     |   2 |                | 4 |     |   * |
                  |------|    |-----|                  |------|    |-----|
                                                          |     \
                                                          |      \
                                                       |------|   |------|
                                                       |2  |     |  5  |
                                                      |------|      |------|




                  ***/
                p = create(ex);
                node *q = new node(DATA,result(p));
                destroy(p);
                p = q;
            }
            if (root == NULL) {
                root = p;
            } else {
                if (root->rc == NULL) {
                    root->rc = p;
                } else {
                    root->rc->rc = p;
                }
            }
            break;
        case CPAREN:
        case EOL:
            return root;
        case ADD:
        case SUB:
            root = new node(reType,0,root);
            break;
        case MULIT:
        case DIV:
            if (root->type == DATA || root->type == MULIT || root->type == DIV) {
                root = new node(reType,0,root);
            } else {
                root->rc = new node(reType,0,root->rc);
            }
            break;
        default:
            return NULL;
            break;
        }

    }
    return root;
}

template <typename T>
typename Calculator<T>::elemType Calculator<T>::getToken(char *&ex, T &value)
{
    char t;
    while(*ex == ' ') ++ex;
    if (*ex >= '0' && *ex <= '9') {
        value = 0;
        while(*ex >= '0' && *ex <= '9') {
            value = value*10 + *ex - '0';
            ++ex;
        }
        return DATA;
    }

    if (*ex == '\0') return EOL;
    t = *ex;
    ++ex;
    switch (t) {
    case '+':
        return ADD;
    case '-':
        return SUB;
    case '*':
        return MULIT;
    case '/':
        return DIV;
    case '(':
        return OPAREN;
    case ')':
        return CPAREN;
    default:
        return EOL;
    }

}

template <typename T>
T Calculator<T>::result()
{
    return result(root);
}

template <typename T>
T Calculator<T>::result(node *r)
{
    elemType t = r->type;
    T t2,t3;
    if (t == DATA) {
        return r->data;
    }
    t2 = result(r->lc);
    t3 = result(r->rc);
    switch (t) {
    case ADD:
        r->data = t2 + t3;
        break;
    case SUB:
        r->data = t2 - t3;
        break;
    case MULIT:
        r->data = t2 * t3;
        break;
    case DIV:
        r->data = t2 / t3;
        break;
    default:
        break;
    }
    return r->data;
}

#endif // CALCULATOR_HPP


int main()
{
    try {
        Calculator<int> ex("(4-2)*(10+(4+6)/2)+2");
        std::cout << ex.result();
    } catch(std::exception &ex) {
        std::cout << ex.what() << std::endl;
    }



    return 0;
}


修复一个bug,可以处理小数,不过不进行检错

template <typename T>
typename Calculator<T>::elemType Calculator<T>::getToken(char *&ex, T &value)
{
    char t;
    while(*ex == ' ') ++ex;
    if (*ex >= '0' && *ex <= '9') {
        value = 0;
        T t = 0;
        T t2 = 1;
        bool f = false;//标识小数点
        while((*ex >= '0' && *ex <= '9') || *ex == '.' ) {
            if (*ex == '.') {
                f = true;
                ++ex;
                continue;
            }
            if (!f) {
                value = value*10 + *ex - '0';
            } else {
                t2 *= 0.1;
                t = t + (*ex - '0')*t2;
            }
            
            ++ex;
        }
        value += t;
        return DATA;
    }
    
    if (*ex == '\0') return EOL;
    t = *ex;
    ++ex;
    switch (t) {
    case '+':
        return ADD;
    case '-':
        return SUB;
    case '*':
        return MULIT;
    case '/':
        return DIV;
    case '(':
        return OPAREN;
    case ')':
        return CPAREN;
    default:
        return EOL;
    }
    
}


修复bug


Balance::elemType Balance::getToken()
{
    elemType re;

    while(*_ex == ' ') ++_ex;

    //这段代码注释掉没有影响,但是会增加函数的调用,性能会受影响
    if (*_ex >= '0' && *_ex <= '9') {
        while((*_ex >= '0' && *_ex <= '9') || *_ex == '.') {
            ++_ex;
        }
        return OTHER;
    }

    switch (*_ex++) {
    case '(':
        re = OPAREN;
        break;
    case ')':
        re = CPAREN;
        break;
    case '\0':
        re = EOL;
        break;
    default://这边处理所有的不是‘(’‘)’‘\0’的情况,不过函数会返回字符串长度+1次
        re = OTHER;
        break;
    }
    return re;
}

template <typename T>
Calculator<T>::Calculator(char *ex) : root(0), _ex(ex)
{
    //    Balance b(ex);
    //    if (!b.balance()) {
    //        throw MyException("() not match!!!");
    //    }
    //在构造函数中爆出异常回导致析构函数不能调用
    //    root = create(ex);
}



template <typename T>
T Calculator<T>::result()
{
    Balance b(_ex);
    if (!b.balance()) {
        throw MyException("() not match!!!");
    }
    root = create(_ex);
    return result(root);
}

_ex为添加的数据成员




  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值