1. 程式人生 > >C++四則運算計算器(能夠處理模運算)

C++四則運算計算器(能夠處理模運算)

閒著沒事做(瘋狂被清華大佬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 + - * / %
//[email protected]
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

相關推薦

C++四則運算計算器(能夠處理運算

閒著沒事做(瘋狂被清華大佬BB說不會寫專案,我怎麼可能不會寫這種計算器,決定瘋狂爆肝寫完證明給他看),決定寫一下部落格,這幾天生活相當不順,轉專業也失敗了,唉。有註釋需要的私聊我,我可以加註釋。這個計算器主要是用的表示式樹進行運算,用了4個部分聯合處理表達式。首先是一個Ope

C語言中的取(%運算

C語言中規定,%運算子的兩個運算元必須同為整數型別,這個很好理解,平時用%也是這麼運算的,問題是如果這兩個運算元異號,那麼最後的計算結果該以哪個運算元的符號為準呢?C99標準中規定,若有a,b兩個整型資料作取模運算,則它們必須滿足以下等式的成立: (a / b) * b +

c#數字圖像處理(九圖像鏡像

scan RR obj spa pos 組成 對稱軸 pixel ppr private void mirror_Click(object sender, EventArgs e) { if

c語言數字影象處理(六:二維離散傅立葉變換

基礎知識 複數表示 C = R + jI 極座標:C = |C|(cosθ + jsinθ) 尤拉公式:C = |C|ejθ 有關更多的時域與複頻域的知識可以學習複變函式與積分變換,本篇文章只給出DFT公式,性質,以及實現方法 二維離散傅立葉變換(DFT) 其中f(x,y)為原影象,F(u,

c語言數字影象處理(九:邊緣檢測

背景知識 邊緣畫素是影象中灰度突變的畫素,而邊緣是連線邊緣畫素的集合。邊緣檢測是設計用來檢測邊緣畫素的區域性影象處理方法。 孤立點檢測 使用<https://www.cnblogs.com/GoldBeetle/p/9744625.html>中介紹的拉普拉斯運算元 輸出影象為 卷積模

c語言數字影象處理(十:閾值處理

定義 全域性閾值處理 假設某一副灰度圖有如下的直方圖,該影象由暗色背景下的較亮物體組成,從背景中提取這一物體時,將閾值T作為分割點,分割後的影象g(x, y)由下述公式給出,稱為全域性閾值處理   多閾值處理 本文僅完成全域性閾值處理的演算法實現 基本全域性閾值處理方法

C++筆記 第六十五課 C++中的異常處理(下---狄泰學院

如果在閱讀過程中發現有錯誤,望評論指正,希望大家一起學習,一起進步。 學習C++編譯環境:Linux 第六十五課 C++中的異常處理(下) 1.C++中的異常處理 catch語句塊中可以丟擲異常 2.問題 為什麼要在catch中重新丟擲異常? 3.C++中的異常

C++筆記 第六十四課 C++中的異常處理(上---狄泰學院

如果在閱讀過程中發現有錯誤,望評論指正,希望大家一起學習,一起進步。 學習C++編譯環境:Linux 第六十四課 C++中的異常處理(上) 1.C++異常處理 C++內建了異常處理的語法元素try…catch… try語句處理正常程式碼邏輯 catch語句處理異常情況 try

C++ Primer Plus--資料處理(三

介紹C++變數的命名規則,以及資料型別 3.1 簡單變數 int a; a = 5; 上述語句告訴程式,它正在儲存整數,並使用名稱a來表示該整數的值。實際上,程式將找到一塊能夠儲存整數的記憶體,將該記憶體單元標記為a,並將5複製到該記憶體單元中,然後,可

c語言數字影象處理(二:圖片放大與縮小-雙線性內插法

int is_in_array(short x, short y, short height, short width) { if (x >= 0 && x < width && y >= 0 && y < height)

c語言數字影象處理(三:仿射變換

1 void bilinera_interpolation(short** in_array, short height, short width, 2 short** out_array, short out_height, short out

c語言數字影象處理(四:灰度變換

灰度變換 灰度變換函式 s = T(r)   其中r為輸入影象在(x, y)點處的灰度值,s為輸出影象在(x, y)點處的灰度值 灰度變換的作用   上圖所示的兩幅T(s)函式的影象曲線,第一幅圖可以增強影象對比度,第二幅圖可以對影象進行二值化處理 灰度變換函式 反轉函式 1 void reverse(s

c語言數字影象處理(五:空間濾波

 空間濾波原理 使用大小為m*n的濾波器對大小為M*N的影象進行線性空間濾波,將濾波器模板乘以影象中對應灰度值,相加得模板中心灰度值                                                                              a = (m-1)

c語言數字影象處理(八:噪聲模型及均值濾波器

影象退化/復原過程模型 高斯噪聲 PDF(概率密度函式) 生成高斯隨機數序列 演算法可參考<http://www.doc.ic.ac.uk/~wl/papers/07/csur07dt.pdf> 程式碼實現 1 double gaussrand() 2 { 3 static

CodeForces 438E The Child and Binary Tree(DP + 生成函式 + 多項式運算

    大致題意:給定一個集合{Cn},一棵二叉樹上的所有節點的點權值從這個集合中選取。現在給定一個m,問對於1..m中的每一個數字i,權值和恰好為i的不同的二叉樹的個數有多少個。這裡形態不同但點權集合的二叉樹視為兩種方案。 與前面做的題目類似,

DCT變換及量化的c++實現(基於opencv矩陣運算

由於DCT的數學原理不好描述,直接放程式碼了: #include<iostream> #include<fstream> #include<opencv2/core/core.hpp> #include<opencv2/highg

C++數字圖像處理(1-伽馬變換

進行 博文 免除 公式 csdn amp cto 輸入 nsf https://blog.csdn.net/huqiang_823/article/details/807670191、算法原理 伽馬變換(冪律變換)是常用的灰度變換,是一種簡單的圖像增強算法。數學公式

運算 C++(快速冪和大數運算

1. 快速冪提高運算速度。傳統冪時間複雜度為O(n),使用快速冪縮小為O(logn),其中n為指數。基本思想:base*=base 這裡就是在算int poww(int a, int b){ // return a ^ b int ans = 1, base = a;

簡易四則運算計算器(C51微控制器實現

【說明】     這是嵌入式課程的一個小作業,用C51微控制器,實現了0-255內的簡易四則運算,暫不支援負數、溢位等特殊情況的處理。 【關鍵點】     1、計算器用R5、R6、R7三位顯示,段碼為0,全暗,段碼為0xff,全亮。     2、R3用於儲存運算子    

C語言中的運算-hdu6124(打表,找規律

題目連結:https://vjudge.net/problem/HDU-6124 題目描述: 題目大意就是給你一個數,判斷這個數 % 其它數後共有幾種結果。 這題對我來說最大的難點是我不太知道每個數 餘 其他的數應該得出什麼結果,後來參考了別人的部落格,才弄清楚了。現在我就舉一些例子來說明一下: