闲着没事做(疯狂被清华大佬BB说不会写项目,我怎么可能不会写这种计算器,决定疯狂爆肝写完证明给他看),决定写一下博客,这几天生活相当不顺,转专业也失败了,唉。有注释需要的私聊我,我可以加注释。
这个计算器主要是用的表达式树进行运算,用了4个部分联合处理表达式。首先是一个Operator类,这个类里面包含了将要用到的运算符,通过继承的方式分别定义各个运算符。也方便对未来可能的运算符进行扩展,可以认为除了数据,都是运算符,包括以后可能扩展的各个函数表达式之类的。
除了Operator类,定义了一棵二叉树,二叉树负责中缀表达式转后缀表达式,里面的转换规则在Operator类里面可以找到,写的很详细。同级运算符处理规则一致,不过直接运算没有在里面实现,而是定义了其他类。Operator类里面对数值的处理用了double类型,考虑到可能有小数点这个操作。(有那么一瞬间我想把小数点当做和左右括号一个优先级认为是运算符。
直接用于计算的类是calculate这个类。特别简单,把表达式树这个类作为calculate类的友元类,就能直接访问root节点了。就是后序遍历处理了,没什么好说的。
最后写了一个Correct_exp类用来修正表达式,比如有5---3和5*-(-3+-2)这种反人类的表示。写的很垃圾,不建议借鉴,有时间再改成一个可以拓展的类,下面是代码。
#ifndef Calculator_H
#define Calculator_H
//maker EternaؼKing 2018 27 / 4 / 2018
//the calculator can support + - * / %
//copyright@ EternaKing
#include<iostream>
#include<string>
#include<cstring>
#include<stack>
class Correct_Expression {
public:
Correct_Expression() = default;
Correct_Expression(const std::string& expression) { Correct_Exp(expression); }
~Correct_Expression() = default;
void Correct_Exp(const std::string& expression) {
Check_Brackets(expression);
correct_exp.clear();
char ahead = ' ';
bool ahead_is_op = false;
int count_number = 0, add_exp = 0, exist_left_brackets = 0, count_pos = 0;
for (auto iter = expression.begin(); iter != expression.end();) {
while (iter != expression.end() && *iter == '+') {
count_pos++;
++iter;
}
while (iter != expression.end() && *iter == '-') {
count_number++;
if (!ahead_is_op) {
ahead = *iter;
ahead_is_op = true;
}
++iter;
}
if (count_number > 0 && count_number % 2 == 0) {
if (ahead == '-')correct_exp.push_back('+');
}
else if (count_number > 0 && count_number % 2) {
if (ahead == '-')correct_exp.push_back('-');
else {
correct_exp.append("(0-");
add_exp++;
}
}
if (count_number == 0&&count_pos>0)
if (iter != expression.end() && isdigit(*iter) && !ahead_is_op || ahead == ')')correct_exp.push_back('+');
count_number = count_pos = 0;
if (isdigit(*iter) || *iter == '.') {
correct_exp.push_back(*(iter++));
ahead_is_op = false;
}
else if (*iter == '*' || *iter == '/'||*iter=='%') {
if (correct_exp.empty() || (ahead_is_op&&ahead != ')')) throw"wrong expression!";
else {
correct_exp.push_back(*iter);
ahead = *iter;
ahead_is_op = true;
}
++iter;
}
else if (*iter == ')') {
exist_left_brackets--;
if (ahead_is_op)throw"wrong expression!";
else {
correct_exp.push_back(*iter);
ahead = *iter;
ahead_is_op = true;
}
++iter;
}
else if (*iter == '(') {
exist_left_brackets++;
if (!ahead_is_op&&!correct_exp.empty())throw"wrong expression!";
else {
correct_exp.push_back(*iter);
ahead = *iter;
ahead_is_op = true;
}
++iter;
}
if (add_exp > 0 && iter != expression.end() && isdigit(*iter) == 0 && exist_left_brackets == 0 && *iter != '(') {
correct_exp.push_back(')');
add_exp--;
}
}
while (add_exp > 0) {
correct_exp.push_back(')');
add_exp--;
}
}
std::string Get_Correct_Exp() { return correct_exp; }
private:
static void Check_Brackets(const std::string& expression) {
std::stack<char> brackets_stack;
for (auto iter = expression.cbegin(); iter != expression.cend(); ++iter)
if (*iter == '(')
brackets_stack.push(*iter);
else if (*iter == ')'&&brackets_stack.size())
brackets_stack.pop();
if (!brackets_stack.empty())
throw"Brackets are not match!";
}
std::string correct_exp = "";
};
struct Tree_Node {
Tree_Node() = default;
Tree_Node(Tree_Node* left, Tree_Node* right, bool is_op, double _value, char _op)
:left_child(left), right_child(right), is_operator(is_op), value(_value), _Operator(_op) {}
~Tree_Node() = default;
public:
Tree_Node* left_child = nullptr;
Tree_Node* right_child = nullptr;
bool is_operator = true;
double value = 0.0;
char _Operator = ' ';
};
std::stack<char> exp_stack;
std::stack<Tree_Node* > node_stack;
class Operator {
public:
virtual ~Operator() = 0;
};
Operator::~Operator() {}
class Manage_Stack :public Operator {
public:
Manage_Stack() = default;
~Manage_Stack()override { Clear(); }
void Clear() {
while (exp_stack.size())exp_stack.pop();
while (node_stack.size())exp_stack.pop();
}
bool Deal_Exp() {
while (!exp_stack.empty()) {
Tree_Node* right = node_stack.top();
node_stack.pop();
Tree_Node* left = node_stack.top();
node_stack.pop();
Tree_Node* new_node = new Tree_Node(left, right, true, 0.0, exp_stack.top());
node_stack.push(new_node);
exp_stack.pop();
}
answer_node = node_stack.top();
node_stack.pop();
return node_stack.empty();
}
Tree_Node* Get_Answer() {return answer_node;}
private:
Tree_Node* answer_node = nullptr;
};
class Number_Operator :public Operator {
public:
~Number_Operator()override = default;
void Deal_Exp(double value) {
Tree_Node* new_node = new Tree_Node(nullptr, nullptr, false, value, ' ');
node_stack.push(new_node);
final_number = integer_part = decimal_part = 0.0;
base = 10;
is_floating = false;
}
void Deal_Exp(int number) {
if (is_floating) {
decimal_part += double(number) / base;
base *= 10;
}
else {
integer_part *= 10;
integer_part += number;
}
final_number = integer_part + decimal_part;
}
void Change_Mode() {is_floating = true;}
double Final_Value()const {return final_number;}
private:
double final_number = 0.0;
double integer_part = 0.0;
double decimal_part = 0.0;
int base = 10;
bool is_floating = false;
};
class Add_Operator :public Operator {
public:
void Deal_Exp() {
if (exp_stack.empty())exp_stack.push(sign);
else if (exp_stack.top() == '(')exp_stack.push(sign);
else {
Tree_Node* right = node_stack.top();
node_stack.pop();
Tree_Node* left = node_stack.top();
node_stack.pop();
Tree_Node* new_node = new Tree_Node(left, right, true, 0.0, exp_stack.top());
node_stack.push(new_node);
exp_stack.pop();
exp_stack.push(sign);
}
}
~Add_Operator()override = default;
private:
char sign = '+';
};
class Subtract_Operator :public Operator {
public:
void Deal_Exp() {
if (exp_stack.empty())exp_stack.push(sign);
else if (exp_stack.top() == '(')exp_stack.push(sign);
else {
Tree_Node* right = node_stack.top();
node_stack.pop();
Tree_Node* left = node_stack.top();
node_stack.pop();
Tree_Node* new_node = new Tree_Node(left, right, true, 0.0, exp_stack.top());
node_stack.push(new_node);
exp_stack.pop();
exp_stack.push(sign);
}
}
~Subtract_Operator()override = default;
private:
char sign = '-';
};
class Multiply_Operator :public Operator {
public:
void Deal_Exp() {
if (exp_stack.empty())exp_stack.push(sign);
else if (exp_stack.top() == '+' || exp_stack.top() == '-' || exp_stack.top() == '(')exp_stack.push(sign);
else {
Tree_Node* right = node_stack.top();
node_stack.pop();
Tree_Node* left = node_stack.top();
node_stack.pop();
Tree_Node* new_node = new Tree_Node(left, right, true, 0.0, exp_stack.top());
node_stack.push(new_node);
exp_stack.pop();
exp_stack.push(sign);
}
}
~Multiply_Operator()override = default;
private:
char sign = '*';
};
class Divide_Operator :public Operator {
public:
void Deal_Exp() {
if (exp_stack.empty())exp_stack.push(sign);
else if (exp_stack.top() == '+' || exp_stack.top() == '-' || exp_stack.top() == '(')exp_stack.push(sign);
else {
Tree_Node* right = node_stack.top();
node_stack.pop();
Tree_Node* left = node_stack.top();
node_stack.pop();
Tree_Node* new_node = new Tree_Node(left, right, true, 0.0, exp_stack.top());
node_stack.push(new_node);
exp_stack.pop();
exp_stack.push(sign);
}
}
~Divide_Operator()override = default;
private:
char sign = '/';
};
class Modulus_Operator :public Operator {
public:
void Deal_Exp() {
if (exp_stack.empty())exp_stack.push(sign);
else if (exp_stack.top() == '+' || exp_stack.top() == '-' || exp_stack.top() == '(')exp_stack.push(sign);
else {
Tree_Node* right = node_stack.top();
node_stack.pop();
Tree_Node* left = node_stack.top();
node_stack.pop();
Tree_Node* new_node = new Tree_Node(left, right, true, 0.0, exp_stack.top());
node_stack.push(new_node);
exp_stack.pop();
exp_stack.push(sign);
}
}
~Modulus_Operator()override = default;
private:
char sign = '%';
};
class Left_Brackets_Operator :public Operator {
public:
void Deal_Exp() {exp_stack.push(sign);}
~Left_Brackets_Operator()override = default;
private:
char sign = '(';
};
class Right_Brackets_Operator :public Operator {
public:
void Deal_Exp() {
while (!exp_stack.empty() && exp_stack.top() != '(') {
Tree_Node* right = node_stack.top();
node_stack.pop();
Tree_Node* left = node_stack.top();
node_stack.pop();
Tree_Node* new_node = new Tree_Node(left, right, true, 0.0, exp_stack.top());
node_stack.push(new_node);
exp_stack.pop();
}
exp_stack.pop();
}
~Right_Brackets_Operator()override = default;
private:
char sign = ')';
};
class Binary_Tree {
public:
virtual void Pre_Order(void(*thevisit)(Tree_Node* node)) = 0;
virtual void In_Order(void(*thevisit)(Tree_Node* node)) = 0;
virtual void Post_Order(void(*thevisit)(Tree_Node* node)) = 0;
virtual void Clear() = 0;
virtual ~Binary_Tree() = 0;
protected:
static void dispose(Tree_Node* node) {
delete node;
}
static void(*visit)(Tree_Node* node);
static void preorder(Tree_Node* node) {
if (node) {
visit(node);
preorder(node->left_child);
preorder(node->right_child);
}
}
static void inorder(Tree_Node* node) {
if (node) {
inorder(node->left_child);
visit(node);
inorder(node->right_child);
}
}
static void postorder(Tree_Node* node) {
if (node) {
postorder(node->left_child);
postorder(node->right_child);
visit(node);
}
}
};
Binary_Tree::~Binary_Tree() {}
void(*Binary_Tree::visit)(Tree_Node* node) = nullptr;
class Expression_Tree :public Binary_Tree {
public:
friend class Calculate;
Expression_Tree() = default;
Expression_Tree(const std::string& expression) {
bool in_deal_number = false;
if (expression[0] == '+' || expression[0] == '-')Num.Deal_Exp(0.0);
for (auto iter = expression.begin(); iter != expression.end(); ++iter) {
if (!isdigit(*iter) && (*iter) != '.')
if (in_deal_number) {
in_deal_number = false;
Num.Deal_Exp(Num.Final_Value());
}
if (isdigit(*iter)) {
Num.Deal_Exp(*iter - '0');
in_deal_number = true;
}
else if (*iter == '.') {
Num.Change_Mode();
in_deal_number = true;
}
else if (*iter == '+')Add.Deal_Exp();
else if (*iter == '-')Sub.Deal_Exp();
else if (*iter == '*')Mul.Deal_Exp();
else if (*iter == '/')Div.Deal_Exp();
else if (*iter == '%')Mod.Deal_Exp();
else if (*iter == '(')LB_op.Deal_Exp();
else if (*iter == ')')RB_op.Deal_Exp();
else if (*iter == ' ')continue;
}
if (in_deal_number)Num.Deal_Exp(Num.Final_Value());
if (Mananer.Deal_Exp())root = Mananer.Get_Answer();
else throw"Wrong Expression";
}
void Clear()override {
Post_Order(dispose);
root = nullptr;
}
void In_Order(void(*thevisit)(Tree_Node* node))override {
visit = thevisit;
inorder(root);
}
void Pre_Order(void(*thevisit)(Tree_Node* node)) override {
visit = thevisit;
preorder(root);
}
void Post_Order(void(*thevisit)(Tree_Node* node))override {
visit = thevisit;
postorder(root);
}
~Expression_Tree() override {Clear();}
private:
Tree_Node* root = nullptr;
Manage_Stack Mananer;
Number_Operator Num;
Add_Operator Add;
Subtract_Operator Sub;
Multiply_Operator Mul;
Divide_Operator Div;
Modulus_Operator Mod;
Left_Brackets_Operator LB_op;
Right_Brackets_Operator RB_op;
};
class Calculate {
public:
Calculate() = default;
Calculate(const std::string& exp) {
corrector.Correct_Exp(exp);
expression = corrector.Get_Correct_Exp();
}
~Calculate() = default;
double Answer() {
Expression_Tree exp_tree(expression);
final_answer = calcute_answer(exp_tree.root);
return final_answer;
}
private:
double final_answer = 0.0;
std::string expression = " ";
Correct_Expression corrector;
static double calcute_answer(Tree_Node* _root) {
double left_answer = 0.0, right_answer = 0.0;
if (_root->is_operator) {
left_answer = calcute_answer(_root->left_child);
right_answer = calcute_answer(_root->right_child);
char operator_now = _root->_Operator;
switch (operator_now) {
case '+':return left_answer + right_answer;
case'-':return left_answer - right_answer;
case'*':return left_answer*right_answer;
case'/':if (right_answer == 0)
throw"Divisor can not be zero!";
else return left_answer / right_answer;
case'%':if (left_answer != int(left_answer) || right_answer != int(right_answer))
throw"Only integer can modulus.";
else return int(left_answer) % int(right_answer);
default: break;
}
}
else return _root->value;
}
};
#endif