找回密码
 中文实名注册
搜索
查看: 508|回复: 0

化学式计算、化学方程式配平、溶液浓度计算、常见化学反应查询

[复制链接]

731

主题

577

回帖

2万

积分

管理员

积分
24978
发表于 2025-8-21 12:45:36 | 显示全部楼层 |阅读模式
[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;
}

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 中文实名注册

本版积分规则

快速回复 返回顶部 返回列表