[C++] 纯文本查看 复制代码
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <vector>
#include <sstream>
#include <algorithm>
#include <cctype>
#include <numeric>
using namespace std;
// 设置输出精度
void setOutputPrecision() {
cout << fixed << setprecision(2);
}
// 常见元素相对原子质量表(初中常用)
map<string, double> elementMasses = {
{"H", 1}, {"He", 4}, {"Li", 7}, {"Be", 9}, {"B", 11},
{"C", 12}, {"N", 14}, {"O", 16}, {"F", 19}, {"Ne", 20},
{"Na", 23}, {"Mg", 24}, {"Al", 27}, {"Si", 28}, {"P", 31},
{"S", 32}, {"Cl", 35.5}, {"K", 39}, {"Ca", 40}, {"Fe", 56},
{"Cu", 64}, {"Zn", 65}, {"Ag", 108}, {"Ba", 137}, {"Mn", 55},
{"Hg", 201}, {"I", 127}, {"Pt", 195}, {"Au", 197}
};
// 常见化学反应(初中重点)
map<string, string> reactions = {
{"1", "镁在空气中燃烧: 2Mg + O₂ 点燃 2MgO (耀眼白光,放热,生成白色固体)"},
{"2", "铁在氧气中燃烧: 3Fe + 2O₂ 点燃 Fe₃O₄ (火星四射,放热,生成黑色固体)"},
{"3", "实验室制氧气(高锰酸钾): 2KMnO₄ △ K₂MnO₄ + MnO₂ + O₂↑"},
{"4", "实验室制氧气(过氧化氢): 2H₂O₂ MnO₂ 2H₂O + O₂↑"},
{"5", "电解水: 2H₂O 通电 2H₂↑ + O₂↑ (正氧负氢,体积比1:2)"},
{"6", "实验室制二氧化碳: CaCO₃ + 2HCl = CaCl₂ + H₂O + CO₂↑"},
{"7", "二氧化碳使澄清石灰水变浑浊: Ca(OH)₂ + CO₂ = CaCO₃↓ + H₂O"},
{"8", "铁与硫酸铜反应: Fe + CuSO₄ = FeSO₄ + Cu (湿法炼铜,铁表面变红)"},
{"9", "盐酸除铁锈: Fe₂O₃ + 6HCl = 2FeCl₃ + 3H₂O (铁锈消失,溶液变黄)"},
{"10", "氢氧化钠与盐酸中和: NaOH + HCl = NaCl + H₂O (放热反应)"}
};
// 1. 化学式计算模块
namespace FormulaCalc {
// 解析化学式,返回元素及其原子个数 (如 "H2SO4" -> {("H",2), ("S",1), ("O",4)})
map<string, int> parseFormula(const string& formula) {
map<string, int> elements;
int n = formula.size();
int i = 0;
while (i < n) {
// 提取元素符号(大写字母开头,可能跟小写字母)
if (!isupper(formula[i])) {
cerr << "错误: 元素符号必须以大写字母开头!" << endl;
return {};
}
string elem;
elem += formula[i];
i++;
if (i < n && islower(formula[i])) {
elem += formula[i];
i++;
}
// 提取原子个数(默认1)
int count = 0;
while (i < n && isdigit(formula[i])) {
count = count * 10 + (formula[i] - '0');
i++;
}
if (count == 0) count = 1;
elements[elem] += count;
}
return elements;
}
// 计算相对分子质量
double molecularMass(const string& formula) {
auto elements = parseFormula(formula);
if (elements.empty() && !formula.empty()) return -1;
double mass = 0;
for (const auto& [elem, count] : elements) {
if (elementMasses.find(elem) == elementMasses.end()) {
cerr << "错误: 未知元素 " << elem << endl;
return -1;
}
mass += elementMasses[elem] * count;
}
return mass;
}
// 计算化合物中元素的质量分数
double massPercentage(const string& formula, const string& element) {
auto elements = parseFormula(formula);
if (elements.empty() && !formula.empty()) return -1;
if (elements.find(element) == elements.end()) {
cerr << "错误: 元素 " << element << " 不在化学式 " << formula << " 中" << endl;
return -1;
}
double totalMass = molecularMass(formula);
if (totalMass <= 0) return -1;
double elemMass = elementMasses[element] * elements[element];
return (elemMass / totalMass) * 100;
}
}
// 2. 化学方程式配平模块(最小公倍数法)
namespace EquationBalancer {
// 解析带系数的化合物,返回元素总个数 (如 "2H2O" -> {("H",4), ("O",2)})
map<string, int> parseCompound(const string& comp) {
map<string, int> elements;
if (comp.empty()) return elements;
// 提取系数
int coeff = 0;
int i = 0;
while (i < comp.size() && isdigit(comp[i])) {
coeff = coeff * 10 + (comp[i] - '0');
i++;
}
if (coeff == 0) coeff = 1;
// 解析化学式
string formula = comp.substr(i);
auto subElements = FormulaCalc::parseFormula(formula);
for (const auto& [elem, count] : subElements) {
elements[elem] += count * coeff;
}
return elements;
}
// 合并多个化合物的元素计数
map<string, int> mergeElements(const vector<string>& compounds) {
map<string, int> total;
for (const auto& comp : compounds) {
auto elem = parseCompound(comp);
for (const auto& [e, c] : elem) {
total[e] += c;
}
}
return total;
}
// 求最大公约数
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// 求最小公倍数
int lcm(int a, int b) {
return a * b / gcd(a, b);
}
// 配平方程式
bool balance(const vector<string>& reactants, const vector<string>& products,
vector<int>& reactCoeffs, vector<int>& prodCoeffs) {
reactCoeffs.assign(reactants.size(), 1);
prodCoeffs.assign(products.size(), 1);
// 简单配平算法(针对初中常见反应)
for (int iter = 0; iter < 100; iter++) { // 限制迭代次数
// 计算当前元素数量
vector<string> reactWithCoeff;
for (int i = 0; i < reactants.size(); i++) {
reactWithCoeff.push_back(to_string(reactCoeffs[i]) + reactants[i]);
}
auto reactElements = mergeElements(reactWithCoeff);
vector<string> prodWithCoeff;
for (int i = 0; i < products.size(); i++) {
prodWithCoeff.push_back(to_string(prodCoeffs[i]) + products[i]);
}
auto prodElements = mergeElements(prodWithCoeff);
// 检查是否配平
bool balanced = true;
string unbalancedElem;
for (const auto& [elem, count] : reactElements) {
if (prodElements[elem] != count) {
balanced = false;
unbalancedElem = elem;
break;
}
}
if (balanced) return true;
// 调整系数(以不平衡元素为目标)
int reactCount = reactElements[unbalancedElem];
int prodCount = prodElements[unbalancedElem];
int commonLcm = lcm(reactCount, prodCount);
// 调整反应物系数
int rFactor = commonLcm / reactCount;
for (int i = 0; i < reactants.size(); i++) {
if (reactants[i].find(unbalancedElem) != string::npos) {
reactCoeffs[i] *= rFactor;
break;
}
}
// 调整生成物系数
int pFactor = commonLcm / prodCount;
for (int i = 0; i < products.size(); i++) {
if (products[i].find(unbalancedElem) != string::npos) {
prodCoeffs[i] *= pFactor;
break;
}
}
}
cerr << "提示: 该反应较复杂,建议手动配平" << endl;
return false;
}
}
// 3. 溶液浓度计算模块
namespace SolutionCalc {
// 溶质质量分数 = 溶质质量/(溶质质量+溶剂质量)×100%
double massFraction(double soluteMass, double solventMass) {
if (soluteMass < 0 || solventMass < 0) {
cerr << "错误: 质量不能为负数" << endl;
return -1;
}
double solutionMass = soluteMass + solventMass;
if (solutionMass == 0) {
cerr << "错误: 溶液质量不能为零" << endl;
return -1;
}
return (soluteMass / solutionMass) * 100;
}
// 溶液稀释计算: c1×m1 = c2×m2
double dilution(double c1, double m1, double c2) {
if (c1 < 0 || c2 < 0 || c1 > 100 || c2 > 100 || m1 < 0) {
cerr << "错误: 浓度应在0-100之间,质量不能为负" << endl;
return -1;
}
if (c2 > c1) {
cerr << "错误: 稀释后浓度不能高于原浓度" << endl;
return -1;
}
return (c1 * m1) / c2; // 稀释后溶液总质量
}
// 一定浓度溶液的配制计算
double soluteRequired(double solutionMass, double concentration) {
if (solutionMass < 0 || concentration < 0 || concentration > 100) {
cerr << "错误: 输入参数无效" << endl;
return -1;
}
return solutionMass * concentration / 100;
}
}
// 菜单函数
void showMainMenu() {
cout << "\n====== 初中化学辅助工具 ======" << endl;
cout << "1. 化学式计算 (相对分子质量/元素质量分数)" << endl;
cout << "2. 化学方程式配平 (简单反应)" << endl;
cout << "3. 溶液浓度计算 (质量分数/稀释问题)" << endl;
cout << "4. 常见化学反应查询" << endl;
cout << "0. 退出程序" << endl;
cout << "请选择功能: ";
}
void formulaMenu() {
cout << "\n====== 化学式计算 ======" << endl;
cout << "1. 计算相对分子质量 (例如: H2O, CO2)" << endl;
cout << "2. 计算元素质量分数 (例如: H在H2O中的质量分数)" << endl;
cout << "0. 返回主菜单" << endl;
cout << "请选择: ";
}
void equationMenu() {
cout << "\n====== 化学方程式配平 ======" << endl;
cout << "说明: 输入反应物和生成物,用逗号分隔(不含系数)" << endl;
cout << "示例: 反应物输入 H2,O2 生成物输入 H2O" << endl;
}
void solutionMenu() {
cout << "\n====== 溶液浓度计算 ======" << endl;
cout << "1. 计算溶质质量分数" << endl;
cout << "2. 计算所需溶质质量" << endl;
cout << "3. 溶液稀释计算" << endl;
cout << "0. 返回主菜单" << endl;
cout << "请选择: ";
}
void reactionMenu() {
cout << "\n====== 常见化学反应查询 ======" << endl;
cout << "1. 镁在空气中燃烧" << endl;
cout << "2. 铁在氧气中燃烧" << endl;
cout << "3. 高锰酸钾制氧气" << endl;
cout << "4. 过氧化氢制氧气" << endl;
cout << "5. 电解水" << endl;
cout << "6. 实验室制二氧化碳" << endl;
cout << "7. 二氧化碳使澄清石灰水变浑浊" << endl;
cout << "8. 铁与硫酸铜反应" << endl;
cout << "9. 盐酸除铁锈" << endl;
cout << "10. 氢氧化钠与盐酸中和" << endl;
cout << "请输入反应编号(0返回): ";
}
int main() {
setOutputPrecision();
int choice;
do {
showMainMenu();
cin >> choice;
cin.ignore(); // 清除输入缓冲区
switch (choice) {
case 1: { // 化学式计算
int subChoice;
do {
formulaMenu();
cin >> subChoice;
cin.ignore();
if (subChoice == 1) {
string formula;
cout << "请输入化学式: ";
getline(cin, formula);
double mass = FormulaCalc::molecularMass(formula);
if (mass > 0) {
cout << formula << "的相对分子质量 = " << mass << endl;
}
}
else if (subChoice == 2) {
string formula, element;
cout << "请输入化学式: ";
getline(cin, formula);
cout << "请输入元素符号: ";
getline(cin, element);
double percentage = FormulaCalc::massPercentage(formula, element);
if (percentage > 0) {
cout << element << "在" << formula << "中的质量分数 = " << percentage << "%" << endl;
}
}
else if (subChoice != 0) {
cout << "无效选择,请重试!" << endl;
}
} while (subChoice != 0);
break;
}
case 2: { // 方程式配平
equationMenu();
string reactantsStr, productsStr;
cout << "请输入反应物: ";
getline(cin, reactantsStr);
cout << "请输入生成物: ";
getline(cin, productsStr);
// 解析输入为化合物列表
vector<string> reactants, products;
stringstream rs(reactantsStr), ps(productsStr);
string item;
while (getline(rs, item, ',')) {
item.erase(remove_if(item.begin(), item.end(), ::isspace), item.end());
if (!item.empty()) reactants.push_back(item);
}
while (getline(ps, item, ',')) {
item.erase(remove_if(item.begin(), item.end(), ::isspace), item.end());
if (!item.empty()) products.push_back(item);
}
// 配平并输出结果
vector<int> reactCoeffs, prodCoeffs;
if (EquationBalancer::balance(reactants, products, reactCoeffs, prodCoeffs)) {
cout << "配平结果: " << endl;
for (int i = 0; i < reactants.size(); i++) {
if (i > 0) cout << " + ";
if (reactCoeffs[i] > 1) cout << reactCoeffs[i];
cout << reactants[i];
}
cout << " → ";
for (int i = 0; i < products.size(); i++) {
if (i > 0) cout << " + ";
if (prodCoeffs[i] > 1) cout << prodCoeffs[i];
cout << products[i];
}
cout << endl;
}
break;
}
case 3: { // 溶液浓度计算
int subChoice;
do {
solutionMenu();
cin >> subChoice;
if (subChoice == 1) {
double solute, solvent;
cout << "请输入溶质质量(克): ";
cin >> solute;
cout << "请输入溶剂质量(克): ";
cin >> solvent;
double fraction = SolutionCalc::massFraction(solute, solvent);
if (fraction >= 0) {
cout << "溶质质量分数 = " << fraction << "%" << endl;
}
}
else if (subChoice == 2) {
double solutionMass, concentration;
cout << "请输入溶液总质量(克): ";
cin >> solutionMass;
cout << "请输入溶质质量分数(%): ";
cin >> concentration;
double solute = SolutionCalc::soluteRequired(solutionMass, concentration);
if (solute >= 0) {
cout << "所需溶质质量 = " << solute << "克" << endl;
cout << "所需溶剂质量 = " << (solutionMass - solute) << "克" << endl;
}
}
else if (subChoice == 3) {
double c1, m1, c2;
cout << "原溶液浓度(%): ";
cin >> c1;
cout << "原溶液质量(克): ";
cin >> m1;
cout << "稀释后浓度(%): ";
cin >> c2;
double m2 = SolutionCalc::dilution(c1, m1, c2);
if (m2 >= 0) {
cout << "稀释后溶液总质量 = " << m2 << "克" << endl;
cout << "需加入溶剂质量 = " << (m2 - m1) << "克" << endl;
}
}
else if (subChoice != 0) {
cout << "无效选择,请重试!" << endl;
}
} while (subChoice != 0);
break;
}
case 4: { // 化学反应查询
string num;
do {
reactionMenu();
getline(cin, num);
if (num == "0") break;
if (reactions.find(num) != reactions.end()) {
cout << reactions[num] << endl;
} else {
cout << "无效编号,请重试!" << endl;
}
} while (true);
break;
}
case 0:
cout << "程序已退出,谢谢使用!" << endl;
break;
default:
cout << "无效选择,请输入0-4之间的数字!" << endl;
}
} while (choice != 0);
return 0;
}