[英]C++: STL linked list - representing a Polynomial
我正在研究一个需要我使用STL链表类来表示多项式的问题。 我已经在获得课程定义方面取得了良好的开端,但是对于下一步该去哪里我感到有点困惑(新手程序员 - 请原谅我潜在的无知)。
class Polynomial
{
public:
Polynomial(); //Default constructor
Polynomial(pair<double,int>); //Specified constructor
void add(Polynomial);
Polynomial multiply(Polynomial);
void print();
private:
list<int> order_terms;
list<double> coeffs;
};
我有两个问题:
1)将术语和系数存储为一对似乎更优雅 - 但是我不确定如何使用STL列表来实现它。
2)关于添加成员函数,我不确定如何实现它,以便我可以定义多项式,然后像这样添加术语:
Polynomial test(pair<3.14,0>);
Polynomial test_2(pair<2,1>);
test.add(test_2);
我遇到的主要问题是如何访问存储在另一个对象中的术语并将其链接到第一个多项式。
任何帮助非常感谢。
编辑:add()函数的代码 - 目前无法正常工作
void Polynomial::add(const Polynomial& rhs)
{
//Perform some sort of sort here to make sure both lists are correctly sorted
//Traverse the list of terms to see if there's an existing nth order
//term in the list on the left-hand-side polynomial.
list<int>::iterator itr;
list<int>::iterator itl;
for(itr=rhs->terms.begin(); itr!=rhs->terms.end(); itr++)
{
bool match=0;
//See if there's an existing terms, if so add to it
for(itl=terms.begin(); itl!=terms.end(); itl++)
{
if(*itl->second)==*itr->second)
{
*itl->first+=*itr->first;
match = 1;
}
}
//If not, this is the first nth order term so just push it onto the list
if(!match){ terms.push_back(*itr); //Perform the sort again }
}
要在list
使用一pair
,您可以执行以下操作: list<pair<double, int> >
- 记下>
之间的空格。 做一些像这样的事情也很好
typedef pair<double, int> TermCoeff;
list<TermCoeff> equation;
list<TermCoeff> equation;
// insert items
equation.sort(coeff_compare);
<utility>
标头中有pair
预定义的比较器函数。 他们比较first
元素,然后在second
的,如果first
是平等的。
对于第二个问题,您应该记住,类的对象可以访问同一类对象的成员变量,即使它们是私有的。 如果你没有在系数中留下任何间隙(在构造函数中填充缺少的那个,并将该对的第二个值设置为0
),这意味着你的add方法可能如下所示:
Polynomial& Polynomial::add(const Polynomial& rhs) {
// constructor should sort all terms and enforce that all terms are present
// lhs = current object (left hand side of operator)
// rhs = other object (right hand side of operator)
// example: lhs.add(rhs)
list<TermCoeff>::const_iterator rhs_iter = rhs.terms.begin();
list<TermCoeff>::iterator lhs_iter = terms.begin();
while(rhs_iter != rhs.terms.end()) {
if (lhs_iter != terms.end()) {
// add because we aren't at the end of current object's terms
lhs_iter->second += rhs_iter->second;
++lhs_iter;
} else {
// insert because we are at the end of current object's terms
terms.push_back(*rhs_iter);
lhs_iter = terms.end(); // keep the iterator at the end
}
++rhs_iter;
}
return *this;
}
int main (int argc, const char * argv[])
{
list<TermCoeff> first, second;
first.push_back(TermCoeff(0, 0.0)); // empty
first.push_back(TermCoeff(1, 5.0));
first.push_back(TermCoeff(2, 5.0));
second.push_back(TermCoeff(0, 6.0));
second.push_back(TermCoeff(1, 0.0)); // empty
second.push_back(TermCoeff(2, 8.0));
second.push_back(TermCoeff(3, 9.0));
Polynomial first_eq(first);
Polynomial second_eq(second);
first_eq.add(second_eq);
first_eq.print();
return 0;
}
请注意,我返回了对当前对象的引用。 在添加方法中这是一件好事,因为这样你可以链接添加:
first.add(second).add(third);
要么
first.add(second.add(third));
其他人已经解释了list<pair<double, int> >
(并且我喜欢shelleybutterfly的建议从列表中派生Polynomial
,除了我让它protected
,而不是public
,所以外部代码不能太自由地弄乱内容列表)。
但是add
函数有点棘手,因为添加两个多项式通常不意味着连接它们或将它们的术语加在一起。 -- and you'll soon see that the lists must be sorted. 该操作实际上更像是 - 您很快就会看到必须对列表进行排序。 (事实上,将多项式表示为向量更自然,但我想这不是赋值。)
我建议你首先实现Polynomial::add(pair<double, int>)
,然后实现另一个( add(Polynomial &)
)。
我不想拼写太多,因为这看起来像是家庭作业。 这足以指向正确的方向吗?
编辑:
如果你修复了一些错误,你的新代码看起来是正确的(尽管效率低下):
void Polynomial::add(const Polynomial& rhs)
{
// Don't forget to implement the sorting routine.
// The iterators must be of the correct type. And itr must be const,
// since you have declared rhs to be a const reference. The compiler
// will not allow you to have an iterator with the power to alter
// a const thing.
list<pair<double,int> >::const_iterator itr;
list<pair<double,int> >::iterator itl;
for(itr=rhs->terms.begin(); itr!=rhs->terms.end(); itr++)
{
bool match=false;
for(itl=terms.begin(); itl!=terms.end(); itl++)
{
// You have an extra parenthesis here, and too much dereferencing.
if(itl->second == itr->second)
{
itl->first+=itr->first;
match = true;
}
}
if(!match)
{ terms.push_back(*itr); //Perform the sort again
} // Be careful not to catch the closing brace in a comment
}
}
一旦它工作,你可以考虑如何使它更清洁,更有效。 例如,如果您在正确的位置insert
新术语,则列表将始终按正确顺序排列,并且不需要sort
例程。
至于使用一对,为什么不使用list<pair<double, int>>
( list< pair<double, int> >
list<pair<double, int>>
用于较旧的编译器)? 或者您甚至可以定义一个单独的类来保存您的对,如下所示:
// example is implemented inline, you could always pull it out to
// your source file; although it's even possible that you could
// do everything inline if you want to allow just including a
// header but not having to link a separate file.
class CoeffAndTerm : public pair<double,int>
{
public:
// if you need it you should put extra functions here to
// provide abstractions:
double getTotalValue()
{
return first * second;
}
}
然后使用
list<CoeffAndTerm> Polynomial;
作为你的变量,甚至是
// same stuff goes for this class RE: the inline function definitions
class Polynomial : public list<CoeffAndTerm>
{
public:
// same goes here for the abstraction stuff maybe things
// like in your current Polynomial class; assuming some
// functions here ...
Polynomial Multiply(Polynomial other)
{
Polynomial Result = new Polynomial();
for (int i=0; i < size(); ++i)
{
Result.addCoeffAndTerm(
new CoeffAndTerm(
other.first * first,
other.second * second
);
}
return Result;
}
}
这样你就可以将多项式作为列表本身的推导。 不确定多项式的确切用法,所以我很难说出哪个更有意义,但我喜欢这种方式更好地作为这种类型的一般规则; 似乎是多项式“是一个”系数和术语列表,它不只是“有”一个。 :)我确信这是有争议的,这又取决于你的代码的实际用法。
对于操作,你可以做参考返回,就像在其他一个例子中一样,但是我已经实现了乘法,而没有修改现有的值,你也可以为Add,Subtract等做。所以,假设第一,第二,第三等等是其他多项式
Polynomial Result = First.Multiply(Second).Add(Third).Subtract(Fourth);
你也可以实现复制构造函数, operator =, operator +, operator *, operator /
然后做一些看起来像普通数学的东西:
Polynomial Result = First * Second + Third - Fourth;
虽然可以使用std :: pair对术语顺序和系数进行分组,但我会反对它:它不是非常易读 - 不清楚'first'和'second'是什么意思,C ++将在数字类型之间隐式转换 - 并且你没有从配对(订购)的附加功能中获益。
相反,创建一个类,如:
class Term {
double coeff_;
int exp_;
public:
Term(double coeff, int exp): coeff_(coeff), exp_(exp) {}
double coefficient() const { return coeff; }
int exponent() const { return exp; }
[...]
};
class Polynomial {
std::list<Term> terms;
[...]
出于性能原因公开字段(例如通过使用struct或公开派生)并不是一个好主意:内联构造函数,getter和setter与直接读取或编写变量一样快,并且它们具有封装实现的优势。
就此而言,您可能希望创建单独的类型来包装多项式系数和指数本身,以避免混淆数字类型,并执行无意义的操作,例如:
class Coefficient {
double val;
public:
explicit Coefficient(double value): val(value) {}
double getValue() { return val; }
double operator*(double rhs) { return val*rhs; }
Coefficient operator+(const Coefficient& rhs) {
return Coefficient(val+rhs.val);
}
[...]
};
等等
另一种可能性:您可以使用结构来表示术语和系数,而不是使用类; 您仍然可以像对象一样定义方法,但默认情况下成员是公共的,这可能是出于效率的原因,特别是如果您正在使用这些东西进行大量处理。 所以,也许:
struct CoeffAndTerm
{
int Term;
double Coeff;
private CoeffAndTerm(int parTerm, double parCoeff)
{
Term = parTerm;
Coeff = parCoeff;
}
public static CoeffAndTerm Make(int parTerm, double parCoeff)
{
return new CoeffAndTerm(parTerm, parCoeff);
}
// etc. and otherwise you can just do things as given in the example
// with the classes deriving from list<pair<int, double>>, e.g.,
// silly example again
public double getTotalValue()
{
return first * second;
}
}
并且在第一个例子中同样适用,再次提供比该例子更直接的访问,但仍然允许将抽象方法直接放在对象上
struct Polynomial : public list<CoeffAndTerm>
{
list<CoeffAndTerm> CoefficientsAndTerms;
Polynomial Multiply(Polynomial other)
{
Polynomial Result = new Polynomial();
for (int i=0; i < size(); ++i)
{
Result.addCoeffAndTerm(
new CoeffAndTerm(
other.first * first,
other.second * second
);
}
return Result;
}
// etc.
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.