5

私は自分のC ++を教えています。

多項式を組み合わせようとしています。このために、単純な値の構成を使用して、単純なクラスを定義 Polynomial<T>しました Term<T>。必要な演算子のオーバーロードを定義しました。Coefficient<T>complex<T>

多項式は項を並べ替えて比較します ( std::sort)。

私は取り組んでいcombineLikeTerms()ます。このメソッドが呼び出されると、最初に別のメンバー メソッドが呼び出され、この項のベクトルが並べ替えられます。例えば:

4x^3 + 5x^2 + 3x - 4 

結果のソートされたベクトルになる可能性があります。

質問:

このベクトルで 2 つの反復子を使用しており、同じ順序の隣接する用語をマージしようとしています。

ソート後の初期ベクトルは次のようになります。

4x^3 - 2x^3 + x^3 - 2x^2 + x ...

関数の反復が完了すると、一時スタック ベクトルは 2x^3 + x^3 - 2x^2 + x のようになります。同様の用語がまだある場合は、再度リファクタリングする必要があります。

どうすればいいですか?私は再帰を使用することを考えています。

// ------------------------------------------------------------------------- //
// setPolynomialByDegreeOfExponent()
// should be called before combineLikeTerms
template <class T>
void Polynomial<T>::setPolynomialByDegreeOfExponent()
{
    unsigned int uiIndex = _uiNumTerms - 1;
    if ( uiIndex < 1 )
    {
        return;
    }
    struct _CompareOperator_
    {
        bool operator() ( math::Term<T> a, Term<T> b )
        {
            return ( a.getDegreeOfTerm() > b.getDegreeOfTerm() );
        } // operator()
    };
    stable_sort( _vTerms.begin(), _vTerms.end(), _CompareOperator_() );
} // setPolynomialByDegreeOfExponent

// ------------------------------------------------------------------------- //
// addLikeTerms()
template <class T>
bool Polynomial<T>::addLikeTerms( const Term<T>& termA, const Term<T>& termB, Term<T>& result ) const
{
    if ( termA.termsAreAlike( termB ) )
    {
        result = termA + termB;
        return true;
    }
    return false;
} // addLikeTerms

// ------------------------------------------------------------------------- //
// combineLikeTerms()
template <class T>
void Polynomial<T>::combineLikeTerms()
{
    // First We Order Our Terms.
    setPolynomialByDegreeOfExponent();
    // Nothing To Do Then
    if ( _vTerms.size() == 1 )
    {
        return;
    }
    Term<T> result; // Temp Variable
    // No Need To Do The Work Below This If Statement This Is Simpler
    if ( _vTerms.size() == 2 )
    {
        if ( addLikeTerms( _vTerms.at(0), _vTerms.at(1) )
    {
        _vTerms.clear();
            _vTerms.push_back( result );
        }
        return;
    }
    // For 3 Ore More Terms
    std::vector<Term<T>> vTempTerms; // Temp storage
    std::vector<Term<T>>::iterator it = _vTerms.begin();
    std::vector<Term<T>>::iterator it2 = _vTerms.begin()+1;
    bool bFound = addLikeTerms( *it, *it2, result );

    while ( it2 != _vTerms.end() )
    {
        if ( bFound )
        {
            // Odd Case Last Three Elems
            if ( (it2 == (_vTerms.end()-2)) && (it2+1) == (_vTerms.end()-1)) )
            {
                vTempTerms.push_back( result );
                vTempTerms.push_back( _vTerms.back() );
                break;
            }
            // Even Case Last Two Elems
            else if ( (it2 == (_vTerms.end()-1)) && (it == (_vTerms.end()-2)) )
            {
                vTempTerms.push_back( result );
                break;
            }
            else
            {
                vTempTerms.push_back( result );
                it += 2;    // Increment by 2
                it2 += 2;          "
                bFound = addLikeTerms( *it, *it2, result );
            }
            }
                else {
                // Push Only First One
                vTempTerms.push_back( *it );
                it++;   // Increment By 1
                it2++;         "
                // Test Our Second Iterator
                if ( it2 == _vTerms.end() )
                {
                    vTempTerms.push_back( *(--it2) );  // same as using _vTerms.back()
                }
                else
                {
                    bFound = addLikeTerms( *it, *it2, result );
                }
            }
        }
        // Now That We Have Went Through Our Container, We Need To Update It
        _vTerms.clear();
        _vTerms = vTempTerms;
        // At This point our stack variable should contain all elements from above,
        // however this temp variable can still have like terms in it.
        // ??? Were do I call the recursion and how do I define the base case
        // to stop the execution of the recursion where the base case is a
        // sorted std::vector of Term<T> objects that no two terms that are alike...
        // I do know that the recursion has to happen after the above while loop
    } // combineLikeTerms

誰かが次のステップを見つけるのを手伝ってくれますか? 表示されているコードのバグや効率の問題についてお知らせいただければ幸いです。私はC++が大好きです

4

2 に答える 2

3

これが現代のC++での私の見解です。

実効係数がゼロの項を削除する追加の最適化に注意してください

自己完結型のサンプル:http://liveworkspace.org/code/ee68769826a80d4c7dc314e9b792052b

更新:このhttp://ideone.com/aHuB8のc++03バージョンを投稿しました

#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>

template <typename T>
struct Term
{
    T coeff;
    int exponent;
};

template <typename T>
struct Poly
{
    typedef Term<T> term_t;
    std::vector<term_t> _terms;

    Poly(std::vector<term_t> terms) : _terms(terms) { }

    void combineLikeTerms()
    {
        if (_terms.empty())
            return;

        std::vector<term_t> result;

        std::sort(_terms.begin(), _terms.end(), 
                [] (term_t const& a, term_t const& b) { return a.exponent > b.exponent; });

        term_t accum = { T(), 0 };

        for(auto curr=_terms.begin(); curr!=_terms.end(); ++curr)
        {
            if (curr->exponent == accum.exponent)
                accum.coeff += curr->coeff;
            else
            {
                if (accum.coeff != 0)
                    result.push_back(accum);
                accum = *curr;
            }
        }        
        if (accum.coeff != 0)
            result.push_back(accum);

        std::swap(_terms, result); // only update if no exception
    }
};

int main()
{
    Poly<int> demo({ { 4, 1 }, { 6, 7 }, {-3, 1 }, { 5, 5 } });

    demo.combineLikeTerms();

    for (auto it = demo._terms.begin(); it!= demo._terms.end(); ++it)
        std::cout << (it->coeff>0? " +" : " ") << it->coeff << "x^" << it->exponent;

    std::cout << "\n";
}
于 2012-10-19T07:19:05.487 に答える
1

多項式を一連のペア (係数、変数) として見る必要があります。

[(係数1,変数1),(係数2,変数2),(係数3,変数3),...]

あなたが説明したように、これを左から右に反復し、変数部分が同一である場合は常に、2 つの隣接するペアを 1 つに結合します (もちろん、これはリストが変数部分で既にソートされていることを前提としています!)。

このリストに変数を共有する要素が3 つ以上ある場合はどうなるでしょうか。それでは、それらを組み合わせ続けてください。本当に、再帰や複雑なことは必要ありません。

反復中の任意の時点で、現在のペアの変数部分を最後に見た変数部分と結合します。それらが同一である場合は、それらを組み合わせて続行します。次に取得するペアに、最後に見たものと同じ可変部分がまだある場合は、それらを再度結合します。これを正しく行うと、重複が残ることはありません。

これを行う方法の例を次に示します。新しいペアリストを作成し、入力リストを反復処理して、入力リストの各項目について、最後に新しいリストにプッシュされた項目と組み合わせるか、新しい要素を新しいリストに追加するかを決定します。 :

#include <utility>
#include <vector>
#include <iostream>

typedef std::vector<std::pair<float,std::string>> Polynomial;

Polynomial combine_like_terms(const Polynomial &poly)
{
  if (poly.empty())
    return poly;

  /* Here we store the new, cleaned-up polynomial: */
  Polynomial clean_poly;

  /* Now we iterate: */    
  auto it = begin(poly);
  clean_poly.push_back(*it);
  ++it;
  while (it != end(poly)) {
    if (clean_poly.back().second == it->second)
      clean_poly.back().first += it->first; // Like term found!
    else
      clean_poly.push_back(*it); // Sequence of like-terms ended!
    ++it;
  }
  return clean_poly;
}

int main()
{
  Polynomial polynomial {
    { 1.0 , "x^2" },
    { 1.4 , "x^3" },
    { 2.6 , "x^3" },
    { 0.2 , "x^3" },
    { 2.3 , "x" },
    { 0.7 , "x" }
  };

  Polynomial clean_polynomial = combine_like_terms(polynomial);
  for (auto term : clean_polynomial)
    std::cout << '(' << term.first << ',' << term.second << ")\n";
  std::cout.flush();

  return 0;
}

必要に応じて、これを簡単にテンプレート化することができます。私floatは係数とstrings変数部分に使用しました。これは、再帰や多数の反復子を並行して使用することなく、これを簡単に実行できることを示す単なるコード例です。

ああ、コードは C++11 用に書かれています。繰り返しますが、これは単なるモデルであり、C++03 用に調整できます。

于 2012-10-19T07:11:32.760 に答える