C ++:STL链表 - 表示多项式

时间:2011-08-22 04:30:28

标签: c++ list stl linked-list

我正在研究一个需要我使用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 }         
}

5 个答案:

答案 0 :(得分:4)

要在pair中使用list,您可以执行以下操作: list<pair<double, int> > - 请注意>之间的空格。做一些像

这样的事也很好
typedef pair<double, int> TermCoeff;
list<TermCoeff> equation;

sort list

list<TermCoeff> equation;
// insert items
equation.sort(coeff_compare);

pair标头中的<utility>有预定义的比较器功能。如果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));

答案 1 :(得分:2)

其他人已解释list<pair<double, int> >(我喜欢shelleybutterfly建议从列表中派生Polynomial,除了我将其protected,而不是public,以便外部代码不是太随意乱用列表的内容。)

但是add函数有点棘手,因为添加两个多项式通常不意味着连接它们或将它们的术语加在一起。该操作实际上更像是合并 - 您很快就会看到必须对列表进行排序。 (事实上​​,将多项式表示为向量更自然,但我猜这不是赋值。)

我建议您首先实施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例程。

答案 2 :(得分:1)

至于使用一对,为什么不使用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等做。所以,假设First,第二,第三等是其他多项式

Polynomial Result = First.Multiply(Second).Add(Third).Subtract(Fourth);

您还可以实现复制构造函数operator =, operator +, operator *, operator /,然后执行看起来像普通数学的事情:

Polynomial Result = First * Second + Third - Fourth;

答案 3 :(得分:1)

虽然可以使用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);
    }
[...]
};

答案 4 :(得分:0)

另一种可能性:您可以使用结构来表示术语和系数,而不是使用类;您仍然可以像对象一样定义方法,但默认情况下成员是公共的,这可能是出于效率的原因,特别是如果您正在使用这些东西进行大量处理。所以,也许:

 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.
}