使用栈来检测表达式括号的匹配,使用二叉树来保存运算的中缀表达式,对表达式树进行后序遍历得到后缀表达式,运算得到表达式的值。
检测配对使用栈保存‘(’符号,当遇到一个‘)’,出栈,若栈空则出错,表达式结束,栈非空也出错。
3*5+2构造二叉树如下
四则运算有优先级和结合关系,在构造二叉树时影响构造的过程。优先级高的运算符深度较深,在后序遍历时,先遍历到。
2+3*5构造二叉树如下
遇到括号,将括号中的看成一个子运算式,使用递归来解决。
在中缀表达式转换事的算法描述如下:
当当前的符号是运算数时,检测当前是否有树根,没有则作为树根,否则作为前一个运算符的右孩子,当根节点没有右孩子则作为右孩子,有右孩子则作为右孩子的右元算数。如果是+或-,那它就是已知的最后一个运算符,将它作为根节点,原来的树作为左子树。如果是*或/,优先级高,就要和根节点做比较,怎么改变。如根节点是+或-,则则应该先运算,所以作为右子树的根节点,原来的子树作为它的左子树。如果是同优先级的,原来的先计算,当前最为根节点,原来作为左子树。
#ifndef EXCEPTIONS_H
#define EXCEPTIONS_H
#include
#include
/**
* @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 _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
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
Calculator::Calculator(char *ex)
{
Balance b(ex);
if (!b.balance()) {
throw MyException("() not match!!!");
}
root = create(ex);
}
template
void Calculator::destroy(node *r)
{
if (r != NULL) {
destroy(r->lc);
destroy(r->rc);
delete r;
}
}
template
typename Calculator::node* Calculator::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 Calculator::elemType Calculator::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
T Calculator::result()
{
return result(root);
}
template
T Calculator::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 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 Calculator::elemType Calculator::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
Calculator::Calculator(char *ex) : root(0), _ex(ex)
{
// Balance b(ex);
// if (!b.balance()) {
// throw MyException("() not match!!!");
// }
//在构造函数中爆出异常回导致析构函数不能调用
// root = create(ex);
}
template
T Calculator::result()
{
Balance b(_ex);
if (!b.balance()) {
throw MyException("() not match!!!");
}
root = create(_ex);
return result(root);
}
_ex为添加的数据成员