我需要开发一个程序来求解线性方程。节目
首先读取一个整数n这是方程的数量。
然后程序读取n包含方程的行。
例如,程序的输入如下:
3
2x1+3x2+4x3=16
1x1+2x2+1x3=8
3x1+1x2+2x3=13
任何操作都应该首先将每个方程转换为
正确的形式。方程本身应具有以下性质
-
变量按字母顺序从左到右排序:
3x2+2x1+4x3=16
应该
2x1+3x2+4x3=16
-
任何变量都应该只出现一次:
4x1+3x2-2x1+4x3=16
应该
2x1+3x2+4x3=16
-
方程中只能出现一个常数项,它应该是
在右手侧:
2x1+3x2+5+4x3-11=10
应该
2x1+3x2+4x3=16
-
系数等于 1 或 -1 时,数字 1 是可选的:
1x1+3x2-1x3=10
可以输入为
x1+3x2-x3=10
到目前为止我所做的如下:
#include<iostream>
#include<string>
#include<sstream>
#include<cstdlib>
using namespace std;
int main() {
int n;
cin >> n;
string eqn[100];
//get eq from user
for (int i = 0; i < n; i++) {
cin >> eqn[i];
}
size_t s = 0;
size_t y = 0;
for (int i = 0; i < n; i++) {
for (int x = 1; x <= ((eqn[i].length() - ((eqn[i].length() - 3) / 4)) / 3); x++)
{
int counter = 0;
ostringstream ss;
ss << x;
string j = ss.str();
for (int t = 0; t < eqn[i].length(); t++) {
y = eqn[t].find("x" + j, y + 1);
if (y < eqn[i].length()) { counter++; }
}
for (int o = 1; o <= counter; o++) {
s = eqn[i].find("x" + j, s + 1);
string x1 = eqn[i].substr(s - 1, 3);
string x2 = x2 + x1;
cout << x1;
}
}
cout << endl;
}
int k; cin >> k;
return 0;
}
但事情变得过于复杂,我不确定这是否是正确的方法..
除了弦方程之外,还有更好的方法来运算弦方程吗?find()
, substr()
?
我应该如何处理这个问题?
我从一个语法图 https://en.wikipedia.org/wiki/Syntax_diagram定义(我不会称之为)一种语言:
然后我将其翻译成手写的解析器。
parse-equation.cc
:
#include <iostream>
#include <algorithm>
int parseDigit(const char *&la)
{
switch (*la) {
case '0': ++la; return 0;
case '1': ++la; return 1;
case '2': ++la; return 2;
case '3': ++la; return 3;
case '4': ++la; return 4;
case '5': ++la; return 5;
case '6': ++la; return 6;
case '7': ++la; return 7;
case '8': ++la; return 8;
case '9': ++la; return 9;
default: return -1; // ERROR!
}
}
int parseNumber(const char *&la)
{
int value = parseDigit(la);
if (value < 0) return -1; // ERROR!
for (;;) {
const int digit = parseDigit(la);
if (digit < 0) return value;
value *= 10; value += digit;
}
}
struct Term {
int coeff; // -1 ... missing
int expon; // -1 ... missing -> ERROR
Term(int coeff = -1, int expon = 0): coeff(coeff), expon(expon) { }
};
Term parseTerm(const char *&la)
{
Term term;
term.coeff = parseNumber(la);
if (*la == 'x') {
++la;
term.expon = parseDigit(la);
if (term.coeff < 0) term.coeff = 1; // tolerate missing coeff. for x
}
return term;
}
struct Expression {
bool error;
int coeffs[10];
Expression(bool error = false): error(error)
{
std::fill(std::begin(coeffs), std::end(coeffs), 0);
}
};
Expression parseExpression(const char *&la)
{
Expression expr;
int sign = +1;
do {
const Term term = parseTerm(la);
if (term.expon < 0) return Expression(true); // ERROR!
expr.coeffs[term.expon] += sign * term.coeff;
switch (*la) {
case '+': sign = +1; ++la; break;
case '-': sign = -1; ++la; break;
case '=': break;
default: return Expression(true); // ERROR!
}
} while (*la != '=');
++la;
// parse right hand side
const int result = parseNumber(la);
if (result < 0) return Expression(true); // ERROR!
expr.coeffs[0] -= result;
// check for extra chars
switch (*la) {
case '\n': ++la;
case '\0': break;
default: return Expression(true); // ERROR!
}
return expr;
}
std::ostream& operator<<(std::ostream &out, const Expression &expr)
{
if (expr.error) out << "ERROR!";
else {
bool empty = true;
for (size_t i = 9; i; --i) {
const int coeff = expr.coeffs[i];
if (coeff) out << coeff << 'x' << i << std::showpos, empty = false;
}
if (empty) out << 0;
out << std::noshowpos << '=' << -expr.coeffs[0];
}
return out;
}
int main()
{
const char *samples[] = {
"2x1+3x2+4x3=16",
"1x1+2x2+1x3=8",
"3x1+1x2+2x3=13",
"2x1+3x2+5+4x3-11=10",
"x1+3x2-x3=10"
};
enum { nSamples = sizeof samples / sizeof *samples };
for (size_t i = 0; i < nSamples; ++i) {
std::cout << "Parse '" << samples[i] << "'\n";
const char *la = samples[i];
std::cout << "Got " << parseExpression(la) << std::endl;
}
return 0;
}
编译为g++
并测试于cygwin http://www.cygwin.org:
$ g++ -std=c++11 -o parse-equation parse-equation.cc
$ ./parse-equation
Parse '2x1+3x2+4x3=16'
Got 4x3+3x2+2x1=16
Parse '1x1+2x2+1x3=8'
Got 1x3+2x2+1x1=8
Parse '3x1+1x2+2x3=13'
Got 2x3+1x2+3x1=13
Parse '2x1+3x2+5+4x3-11=10'
Got 4x3+3x2+2x1=16
Parse 'x1+3x2-x3=10'
Got -1x3+3x2+1x1=10
$
Coliru 上的生活演示 http://coliru.stacked-crooked.com/a/c2d05714af0afe66
Note:
代替parseDigit()
and parseNumber()
, std::strtol() http://en.cppreference.com/w/cpp/string/byte/strtol可用于。这将显着减少代码。
I used const char*
对于“读头”la
(...“向前看”的缩写)。纯 C++ 方式可能是std::stringstream
or a std::string::iterator https://stackoverflow.com/q/1995109/7478597但是,也许我还不太习惯这些新奇的东西。对我来说,const char*
是最直观的方式...
The result on right hand side is simply subtracted from the coefficient for x0. So, either the right hand side is 0, or the negative coefficient for x0 becomes right hand side. For my pretty-printing operator<<()
, I chose the latter option.
错误处理相当差,可以通过有关解析失败原因的更详细信息来增强。我省略了这一点,以免进一步“破坏”代码。
可以轻松增强解析器以跳过任何适当位置的空白。这将提高便利性。
在当前状态下,右侧的结果可能不是负数。我将此扩展保留为练习。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)