Input_iterator, find_if и модуль - PullRequest
       18

Input_iterator, find_if и модуль

0 голосов
/ 06 августа 2010

Я реализовал итератор, у которого на выходе есть числа Фибоначчи. В моем main () я хотел бы найти число, которое делится на 17 (это 34). Почему не работает мое утверждение find_if.

Спасибо!

  #include <boost/operators.hpp>
  #include <algorithm>
  #include <tr1/functional>

    struct FibIter: boost::input_iterator_helper<FibIter,unsigned long long> {

 //typedef value_type unsigned long long;
 FibIter(value_type l=0):counter(0), fib0(0),fib1(1){
  while(l!=counter)
   ++(*this);
 }

 value_type operator*() const {return fib0;}
 FibIter& operator++() {
  ++counter; 
  value_type fnew = fib0+fib1;
  fib0 = fib1;
  fib1 = fnew;
  return *this;
  }
 bool operator==(FibIter const &other)const {
  return counter == other.counter;
 }


    private:
 value_type counter;
 value_type fib0, fib1;
    };

    using namespace std;
    using namespace tr1;
    using namespace placeholders;

    int main() {
 FibIter found = find_if(FibIter(), FibIter(100),bind(not2(modulus<unsigned long long>()),_1,17ULL));
    }

Ответы [ 4 ]

0 голосов
/ 13 декабря 2012

Прежде всего, вы можете использовать std::advance(*this,l); вместо этого цикла while в вашем конструкторе.Но!Ваш подход крайне неэффективен , потому что он должен вычислять последовательность Фибоначчи дважды : один, чтобы знать, что является последним числом Фибоначчи, и второй, чтобы фактически получить его, когда используется ++по клиентскому коду.

Я думаю, что лучшим подходом было бы сохранить индекс числа Фибоначчи last из конструктора в закрытом элементе и сравнивать счетчик с ним после каждого ++.Его можно повторно использовать из уже существующего поля index, сделав его следующим образом:

Пусть конструктор по умолчанию инициализирует итератор Фибоначчи fib0 = 0, fib1 = 1 и index = 0.Другой конструктор (параметрический) будет создавать фиктивный итератор, который содержит только последний индекс последовательности, а другие поля недопустимы.Этот один итератор будет итератором «один за другим», только для сравнения индексов, а не для чтения значений.

Итак, вот мое решение:

#include <iterator>

class Fibonacci : public iterator<input_iterator_tag, int>
{
    unsigned index;
    value_type fib0, fib1;
 public:
    Fibonacci(): index(0), fib0(0), fib1(1) { }
    explicit Fibonacci(unsigned last): index(last), fib0(0), fib1(0) { }
    bool operator == (const Fibonacci& other) { return index == other.index; }
    bool operator != (const Fibonacci& other) { return !(*this == other); }
    value_type operator * () const { return fib0; }
    Fibonacci& operator ++ () {
        ++index;
        value_type fnew = fib0 + fib1;
        fib0 = fib1; fib1 = fnew;
        return *this;
    }
    Fibonacci operator ++ (int) {
        Fibonacci current(*this);
        ++(*this);
        return current;
    }
};

#include <iostream>
#include <algorithm>

int main()
{
    using namespace std;
    ostream_iterator<int> out(cout, "; ");
    cout << "Fibonacci numbers from 0th to 19th:\n";
    copy(Fibonacci(), Fibonacci(20), out);
    cout << endl;
}

Вывод:

Fibonacci numbers from 0th to 19th:
0; 1; 1; 2; 3; 5; 8; 13; 21; 34; 55; 89; 144; 233; 377; 610; 987; 1597; 2584; 4181;

Как вы можете видеть, в моем примере также есть многократное повторное использование кода: я повторно использую операторы внутри других операторов, вызывая их.

Конечно, это работает только для чисел, вписывающихся в int,Было бы лучше переписать его, чтобы использовать числа с множественной точностью (например, библиотека GMP).

0 голосов
/ 06 августа 2010

Я думаю, что если вы начнете с первого числа, которое равно 0, команда find вернет его ( modulus (0,17) = 0 ).

0 голосов
/ 06 августа 2010

Хорошо, я решил это, используя! Boost :: bind (...) вместо tr1 :: bind.

0 голосов
/ 06 августа 2010
bind(not2(modulus<unsigned long long>()),_1,17ULL)

должно быть

not1(bind(modulus<unsigned long long>(),_1,17ULL))
...