介绍
在本文中,我们将探讨一个C++程序,该程序可以计算包含分数和幂运算的数学表达式。首先,我们将通过一系列功能强大的函数来简化和执行基本的分数运算(加、减、乘、除)。然后,我们将展示如何使用这些函数和
步骤 1: 定义分数运算函数
在我们的程序中,我们首先定义了一系列函数来执行基本的分数运算。这些函数包括:
1.1 gcd函数
该函数使用递归方式来计算两个数的最大公约数。
int gcd(int a, int b) {
if (b == 0)
return a;
return gcd(b, a % b);
}
1.2 simplify函数
该函数用于简化分数,确保分母始终为正。
std::vector<int> simplify(int numerator, int denominator) {
int divisor = gcd(std::abs(numerator), std::abs(denominator));
numerator /= divisor;
denominator /= divisor;
// 确保分母为正
if (denominator < 0) {
numerator = -numerator;
denominator = -denominator;
}
return { numerator, denominator };
}
1.3 基本数学运算函数
我们定义了函数来执行基本的分数运算,如加法、减法、乘法和除法。
std::vector<int> add(const std::vector<int>& a, const std::vector<int>& b);
std::vector<int> subtract(const std::vector<int>& a, const std::vector<int>& b);
std::vector<int> multiply(const std::vector<int>& a, const std::vector<int>& b);
std::vector<int> divide(const std::vector<int>& a, const std::vector<int>& b);
1.4 power函数
该函数用于计算分数的幂。
std::vector<int> power(const std::vector<int>& a, int n);
步骤 2: 解析和计算表达式
在第二部分中,我们定义了一个calc
函数,它可以解析和计算含有基本数学运算符和括号的表达式。
2.1 初始化
我们首先初始化了几个栈来存储数字和运算符,并对输入字符串进行了一些预处理。
vector<int>calc(string s)
{
char c;//符号
vector<int> a, b, val;//左操作数、右操作数、计算结果
stack<vector<int>> num;//存数字
stack<char> op;//存操作符
//以+或-开头,在开头补零
if (s[0] == '+' || s[0] == '-')
{
s = "0" + s;
}
//将第一个数字压入分数栈
stringstream ss(s);
int t1;
ss >> t1;
val.push_back(t1);
val.push_back(1);
num.push(val);
//每次读取一个符号和数字
while (ss >> c >> val[0])
{
//如果符号是*/,直接与前面的数计算,消去*/
if (c == '*' || c == '/')
{
if (c == '*')
{
val = multiply(val, num.top());
}
else
{
val = divide(num.top(), val);
}
num.pop();//弹出已经计算过的数
num.push(val);//压入计算后的结果
val[1] = 1;
}
else//符号是+-
{
//将取到的数和符号压栈,op栈中只留+-
num.push(val);
op.push(c);
}
}
//操作符栈不为空,只有加减运算
while (!op.empty())
{
a = num.top();
num.pop();
b = num.top();
num.pop();
if (op.top() == '+')
{
num.push(add(a,b));
}
else
{
num.push(subtract(b,a));
}
op.pop();
}
return num.top();
}
2.2 处理乘法和除法
我们使用一个循环来读取每个字符,并用条件语句来处理乘法和除法运算。
if (c == '*' || c == '/') {
...
}
2.3 处理加法和减法
接着我们处理加法和减法运算。
else {
...
}
2.4 计算剩余的加减运算
在循环结束后,我们计算栈中剩余的加减运算。
while (!op.empty()) {
...
}
步骤 3: 主函数
最后,在主函数中,我们使用一个无限循环来读取用户的输入,并调用我们之前定义的calc
函数来计算表达式的结果。
3.1 处理幂运算
我们首先处理输入字符串中的幂运算。
while (1) {
...
for (int i = 0; i < str.size(); i++) {
if (str[i] == '^') {
...
}
}
...
}
3.2 处理括号
然后,我们使用一个循环和一个栈来处理表达式中的括号。
stack<int> kuohao;
int len = str.size();
int from, to;
for (int i = 0; i < len; i++) {
...
}
3.3 输出结果
最后,我们调用calc
函数来计算最终的结果,并将结果输出到控制台。
vector<int> result = calc(str);
cout << result[0] << endl;
if (result[1] != 1) {
cout << "----" << endl;
cout << result[1] << endl;
}
步骤4:源代码
#include<iostream>
#include<string>
#include<sstream>
#include<stack>
#include<algorithm>
#include<vector>
using namespace std;
int gcd(int a, int b) {
if (b == 0)
return a;
return gcd(b, a % b);
}
std::vector<int> simplify(int numerator, int denominator) {
int divisor = gcd(std::abs(numerator), std::abs(denominator));
numerator /= divisor;
denominator /= divisor;
// 确保分母为正
if (denominator < 0) {
numerator = -numerator;
denominator = -denominator;
}
return { numerator, denominator };
}
std::vector<int> add(const std::vector<int>& a, const std::vector<int>& b) {
int numerator = a[0] * b[1] + b[0] * a[1];
int denominator = a[1] * b[1];
return simplify(numerator, denominator);
}
std::vector<int> subtract(const std::vector<int>& a, const std::vector<int>& b) {
int numerator = a[0] * b[1] - b[0] * a[1];
int denominator = a[1] * b[1];
return simplify(numerator, denominator);
}
std::vector<int> multiply(const std::vector<int>& a, const std::vector<int>& b) {
int numerator = a[0] * b[0];
int denominator = a[1] * b[1];
return simplify(numerator, denominator);
}
std::vector<int> divide(const std::vector<int>& a, const std::vector<int>& b) {
int numerator = a[0] * b[1];
int denominator = a[1] * b[0];
return simplify(numerator, denominator);
}
std::vector<int> power(const std::vector<int>& a, int n) {
if (n == 0) {
return { 1, 1 }; // 任何数的0次方都是1
}
else if (n > 0) {
return multiply(a, power(a, n - 1));
}
else {
std::vector<int> reciprocal = { a[1], a[0] };
return power(reciprocal, -n);
}
}
vector<int>calc(string s)
{
char c;//符号
vector<int> a, b, val;//左操作数、右操作数、计算结果
stack<vector<int>> num;//存数字
stack<char> op;//存操作符
//以+或-开头,在开头补零
if (s[0] == '+' || s[0] == '-')
{
s = "0" + s;
}
//将第一个数字压入数字栈
stringstream ss(s);
int t1;
ss >> t1;
val.push_back(t1);
val.push_back(1);
num.push(val);
//每次读取一个符号和数字
while (ss >> c >> val[0])
{
//如果符号是*/,直接与前面的数计算,消去*/
if (c == '*' || c == '/')
{
if (c == '*')
{
val = multiply(val, num.top());
}
else
{
val = divide(num.top(), val);
}
num.pop();//弹出已经计算过的数
num.push(val);//压入计算后的结果
val[1] = 1;
}
else//符号是+-
{
//将取到的数和符号压栈,op栈中只留+-
num.push(val);
op.push(c);
}
}
//操作符栈不为空,只有加减运算
while (!op.empty())
{
a = num.top();
num.pop();
b = num.top();
num.pop();
if (op.top() == '+')
{
num.push(add(a,b));
}
else
{
num.push(subtract(b,a));
}
op.pop();
}
return num.top();
}
int main()
{
while (1) {
string str;//表达式字符串
getline(cin, str);
for (int i = 0; i < str.size(); i++) {
if (str[i] == '^') {
int begin1 = i - 1, end1 = i + 1;
while (isdigit(str[end1]) && end1 < str.size()) {
end1++;
}
if (isdigit(str[begin1])) {
while (isdigit(begin1) && begin1 >= 0) {
begin1--;
}
int num1 = stoi(str.substr(begin1, i - begin1));
int num2 = stoi(str.substr(i + 1, end1 - i));
string swap1;
swap1 += to_string(num1);
for (int i = 0; i < num2 - 1; i++) {
swap1 += "*";
swap1 += to_string(num1);
}
str.erase(begin1, end1 - begin1 + 1);
str.insert(begin1, swap1);
}
else if (str[begin1] == ')') {
int ju = 1;
begin1--;
while (begin1 >= 0) {
if (str[begin1] == ')') {
begin1--;
ju++;
}
else if (str[begin1] == '(') {
begin1--;
ju--;
}
else {
begin1--;
}
if (ju == 0) {
begin1++;
break;
}
}
string num1 = str.substr(begin1, i - begin1);
int num2 = stoi(str.substr(i + 1, end1 - i));
string swap1;
swap1 += num1;
for (int i = 0; i < num2 - 1; i++) {
swap1 += "*";
swap1 += num1;
}
str.erase(begin1, end1 - begin1 + 1);
str.insert(begin1, swap1);
}
}
}
for (int i = 0; i < str.size() - 1; i++) {
if (str[i] == ')' && str[i + 1] == '(') {
str.insert(i+1, "*");
}
}
cout << str << endl;
stack<int> kuohao;//存括号
int len = str.size();
int from, to;
for (int i = 0; i < len; i++)
{
if (str[i] == '(' || str[i] == ')')
{
//括号不匹配
if (kuohao.empty() || str[i] == str[kuohao.top()])
{
kuohao.push(i);//栈里存放的是'('')'在str中的index
}
else//括号匹配
{
from = kuohao.top();
to = i; //定位到一组()
kuohao.pop();//计算过的出栈
//求解括号中的表达式
vector<int> tmp = calc(str.substr(from + 1, to - from - 1));
//把所求结果替换掉括号部分的表达式
stringstream ss;
ss << tmp[0];
ss << "/";
ss << tmp[1];
string tmpS;
ss >> tmpS; //double->string
str.replace(str.begin() + from, str.begin() + to + 1, tmpS.begin(), tmpS.end());//'('...')'之间有to-from+1个字符!
len = str.size();//循环条件记得更新
i = from - 1;
}
}
}
vector<int> result = calc(str);
cout << result[0] << endl;
if (result[1] != 1) {
cout << "----" << endl;
cout << result[1] << endl;
}
}
}
结论
通过这篇文章,我们已经学会了如何创建一个能够处理复杂数学表达式的C++程序。通过使用栈数据结构和递归,我们能够轻松地解析和计算包含分数、幂运算和括号的表达式。希望你找到这篇文章有用!
最后感谢@zdluffy的文章