[C++] 配平化學方程式演算法的封裝
阿新 • • 發佈:2018-12-08
有人已經實現了配平的方法,在此不再重複介紹。
但是,上述的方法所提供的程式碼還是存在著問題,需要進一步修改。
首先,因為 frac 這個結構的成員函式和其它操作函式已被宣告並定義至一個單一的檔案裡,
因此,首先要將它的宣告和定義分開來。把 frac 結構體抽離至封裝的類以外,作為前置宣告。
因為原始碼是直接 printf() 輸出的,而我們需要的是獲取它輸出的結果。
所以,改變它輸出的位置,宣告一個 string ,將配好以後的結果直接賦值到 string 裡。
最終程式碼實現:
[C++ 原始碼]
1 /* Exzh Cross Platfrom Toolkit (ECPT) Qt Version 2 * (This file is the part of the ECPT Project) 3 * Author: Exzh_PMGI 4 * E-mail: [email protected] 5 * License: LGPL v3.0 / Exzh Commerical License 6 * Copyright: (C) Exzh_PMGI 7 * Qt Framework 5.10 has been tested successfully8 * If you want to use the code for business, 9 * please contact me by my email. 10 */ 11 12 #include "exequationbalancer.h" 13 14 #include <QDebug> 15 16 int gcd(int x, int y) { 17 return x % y == 0 ? y : gcd(y, x%y); 18 } 19 20 int lcm(int x, int y) { 21 return x * y / gcd(x, y);22 } 23 24 frac createFrac(int a, int b) 25 { 26 frac tmp = { a,b }; 27 return tmp; 28 } 29 30 frac Abs(frac x) { 31 int p = x.a>0 ? x.a : -x.a, q = x.b>0 ? x.b : -x.b; 32 return createFrac(p, q); 33 } 34 35 string exEquationBalancer::getResult(string inputstr) 36 { 37 strcpy(s,inputstr.c_str()); 38 int lst = 0; 39 for (int i = 1;i<strlen(s);i++) { 40 if (i == strlen(s) - 1)scan(lst, i); 41 if (s[i] == '+' || s[i] == '=') 42 { 43 scan(lst, i - 1); 44 lst = i + 1; 45 } 46 if (s[i] == '=')flag = -1; //等號後面的係數變負 47 } 48 if (Solve()) 49 for (int i = 1;i <= c2 - 1;i++) 50 ans[i] = M[i][N + 1]; 51 else output+="No Solution"; 52 int tmp = lcm(ans[1].b, ans[2].b); 53 for (int i = 3;i <= c2;i++)tmp = lcm(tmp, ans[i].b); 54 for (int i = 1;i <= c2;i++)Ans[i] = ans[i].a*tmp / ans[i].b; //取分母Lcm,把分數變整數 55 for (int i = 1;i <= c2;i++) 56 { 57 if (Ans[i]>1) output+=to_string(Ans[i]); 58 for (int j = 0;j<strlen(mat[i]);j++) 59 output+=mat[i][j]; 60 if (i == c2) 61 { 62 return output; 63 qDebug()<<QString::fromStdString(output); 64 } 65 else if (i == c1) output+="="; 66 else output+="+"; 67 } 68 } 69 70 bool exEquationBalancer::Solve() { //解方程 (矩陣 高cnt,寬c2+1,c2+1列常數全0) 71 ans[c2] = 1; //令最後一個解為1 72 for (int i = 1;i <= cnt;i++) { 73 for (int j = 1;j <= c2;j++) 74 M[i][j] = fun[i][j]; 75 } 76 for (int i = 1;i <= cnt;i++) 77 M[i][c2].a = -M[i][c2].a; //移到常數 78 //高斯消元過程 79 N = c2 - 1, K = cnt; 80 for (int k = 1;k <= N;k++) { 81 frac maxm = createFrac(-1, 1); 82 int maxi; 83 for (int i = k;i <= K;i++) 84 if (maxm<Abs(M[i][k])) 85 maxm = Abs(M[i][k]), maxi = i; 86 if (maxm == createFrac(0, 1)) 87 return false; 88 if (maxi != k) 89 for (int j = 1;j <= N + 1;j++) { 90 swap(M[k][j], M[maxi][j]); 91 } 92 frac tmp = M[k][k]; 93 for (int j = 1;j <= N + 1;j++) 94 M[k][j] = M[k][j] / tmp; 95 for (int i = k - 1 ? 1 : 2;i <= K;i++) { 96 if (i == k)continue; 97 frac tmp = M[i][k]; 98 for (int j = 1;j <= N + 1;j++) 99 M[i][j] = M[i][j] - tmp * M[k][j]; 100 } 101 } 102 return true; 103 } 104 105 void exEquationBalancer::scan(int l, int r) { //處理物質 106 c2++; 107 for (int i = 0;i <= r - l;i++)mat[c2][i] = s[l + i]; //存下元素的名字 108 if (flag == 1)c1++; //統計一下反應物數量 109 int tmp = 1; //tmp是小括號倍數 110 for (int i = l;i <= r;i++) { 111 if (s[i] == ')')tmp = 1; 112 if (s[i] == '(') { 113 int j = i + 1;while (s[j] != ')')j++; //找這個括號的範圍 114 tmp = getint(j); //讀")"右邊的數字 115 } 116 if (s[i] >= 'A'&&s[i] <= 'Z') { //發現元素 117 int x = s[i] - 'A' + 1, y = 0; 118 if (s[i + 1] >= 'a'&&s[i] <= 'z') //看一眼是一個字母的還是兩個的 119 y = s[i + 1] - 'a' + 1; 120 if (!Map[x][y])Map[x][y] = ++cnt; //判重 121 fun[Map[x][y]][c2] += flag * getint(i)*tmp; //把這個物質裡的這種元素數量放進矩陣裡,座標(map[x][y],c2) 122 } 123 } 124 } 125 126 int exEquationBalancer::getint(int pos) { //讀數 127 pos++; 128 if (s[pos] >= 'a'&&s[pos] <= 'z')pos++; 129 if (s[pos]<'0' || s[pos]>'9')return 1; //沒數就是1 130 else { 131 int x = 0; 132 while (s[pos] >= '0'&&s[pos] <= '9')x = x * 10 + s[pos] - '0', pos++; //讀元素後面的數字 133 return x; 134 } 135 } 136 137 void exEquationBalancer::print() { 138 output += to_string(N); 139 output += " "; 140 output += to_string(K); 141 output += "\n"; 142 for (int i = 1;i <= K;i++) { 143 for (int j = 1;j <= N + 1;j++) 144 { 145 output += to_string(M[i][j].a); 146 output += " "; 147 } 148 output += "\n"; 149 } 150 output += "\n"; 151 }
[C++ 標頭檔案]
1 /* Exzh Cross Platfrom Toolkit (ECPT) Qt Version 2 * (This file is the part of the ECPT Project) 3 * Author: Exzh_PMGI 4 * E-mail: [email protected] 5 * License: LGPL v3.0 / Exzh Commerical License 6 * Copyright: (C) Exzh_PMGI 7 * Qt Framework 5.10 has been tested successfully 8 * If you want to use the code for business, 9 * please contact me by my email. 10 */ 11 12 #ifndef EXEQUATIONBALANCER_H 13 #define EXEQUATIONBALANCER_H 14 15 #include <string> 16 #include "../exstdc++.h" 17 18 using namespace std; 19 static string output; 20 int lcm(int x, int y); 21 int gcd(int x, int y); 22 23 struct frac { //分數類 24 int a, b; 25 void reduce() { 26 int x = gcd(a, b); 27 a /= x, b /= x; 28 } 29 frac createFrac(int a, int b) 30 { 31 frac tmp = { a,b }; 32 return tmp; 33 } 34 frac operator = (int x) { 35 a = x, b = 1; 36 return *this; 37 } 38 frac operator = (const frac x) { 39 a = x.a, b = x.b; 40 reduce(); 41 return *this; 42 } 43 frac operator + (const frac x) { 44 return createFrac(b*x.a + a * x.b, b*x.b); 45 } 46 frac operator - (const frac x) { 47 return createFrac(a*x.b - b * x.a, b*x.b); 48 } 49 frac operator * (const frac x) { 50 return createFrac(a*x.a, b*x.b); 51 } 52 frac operator / (const frac x) { 53 return createFrac(a*x.b, b*x.a); 54 } 55 bool operator < (const frac x) { 56 return a * x.b<b*x.a; 57 } 58 bool operator == (const frac x) { 59 return a * x.b == b * x.a; 60 } 61 void print() { 62 if (b == 1) 63 { 64 output += to_string(a); 65 output += "\n"; 66 } 67 else 68 { 69 output += to_string(a); 70 output += "/"; 71 output += to_string(b); 72 } 73 } 74 }; 75 76 frac createFrac(int a, int b); 77 frac Abs(frac x); 78 79 class exEquationBalancer 80 { 81 public: 82 string getResult(string inputstr); 83 84 private: 85 bool Solve(); 86 void scan(int l, int r); 87 int getint(int pos); 88 void print(); 89 90 char s[55]; 91 int fun[55][55]; 92 int Map[27][27]; //手動MAP 93 frac M[55][55]; //求解矩陣 94 frac ans[55]; //解 95 int Ans[55]; //整數解 96 int cnt, c1, c2, flag = 1, N, K; //cnt數元素,c1數反應物,c2總數 (未知數的數量) 97 char mat[55][55]; //儲存物質的名稱 98 }; 99 100 #endif // EXEQUATIONBALANCER_H