582484 Algorithm Libraries

Exercise 2 solutions

  1. int_range_iterator now models the random access iterator concept completely. Conformance is tested using the Boost concept check library.

    #include <iostream>
    #include <iterator>
    #include <string>
    #include <boost/concept_check.hpp>
    
    class int_range_iterator 
      : public std::iterator<std::random_access_iterator_tag, int, ptrdiff_t,
    			 const int*, const int&>
    {
    public:
      int_range_iterator(int i = 0) : i_(i) {}
      // implicit copy constructor, copy assignment and destructor
    
      const int& operator* () const { return i_; }
    
      pointer
      operator->() const { return &i_; }
    
      int_range_iterator& operator++ () { ++i_; return *this; }
    
      int_range_iterator operator++ (int) {
        int_range_iterator tmp = *this; ++*this; return tmp; }
    
      int_range_iterator& operator+=(difference_type n) { i_+=n; return *this; }
    
      int_range_iterator& operator--() { --i_; return *this; }
    
      int_range_iterator operator--(int) {
        int_range_iterator tmp = *this; --*this; return tmp; }
    
      int_range_iterator& operator-=(difference_type n) { i_-=n; return *this; }
    
      friend
      int_range_iterator operator-(int_range_iterator iter, difference_type n) { 
        return iter-= n;
      }
    
      friend
      int operator-(int_range_iterator iter1, 
    		int_range_iterator iter2) {
        return iter1.i_ - iter2.i_;
      }
      
      friend
      int_range_iterator operator+(int_range_iterator iter, difference_type n) { 
        return iter+= n;
      }
    
      friend
      int_range_iterator operator+(difference_type n, int_range_iterator iter) { 
        return iter+=n;
      }
    
      int
      operator[](difference_type n) {
        return i_+n;
      }
    
      bool operator== (const int_range_iterator& other) const {
        return i_ == other.i_;
      }  
    
      bool operator!= (const int_range_iterator& other) const {
        return i_ != other.i_;
      }
    
      bool operator<(const int_range_iterator& other) const {
        return i_ < other.i_;
      }
    
      bool operator>(const int_range_iterator& other) const {
        return i_ > other.i_;
      }
    
      bool operator<=(const int_range_iterator& other) const {
        return i_ <= other.i_;
      }
    
      bool operator>=(const int_range_iterator& other) const {
        return i_ >= other.i_;
      }
    
    private:
      int i_;
    };
    
    int main()
    {
      boost::function_requires<boost::RandomAccessIteratorConcept<int_range_iterator> >();
      return 0;
    }
    
    
  2. adjacent_find

    #include <iterator>
    #include <algorithm>
    #include <iostream>
    
    // because of using input iterators, we have to return an iterator
    // to the latter one of the adjacent values
    template <class InputIterator>
    InputIterator
    adjacent_find (InputIterator begin, InputIterator end) 
    {
    
      if (begin == end) return end;
      typename std::iterator_traits<InputIterator>::value_type value = *begin;
    
      while (++begin != end) {
        if (*begin == value) return begin;
        value = *begin;
      }
      return end;
    }
     
    bool
    check(std::string s)
    {
      std::string::iterator i, j;
    
      i = std::adjacent_find(s.begin(), s.end());
    
      j = ::adjacent_find(s.begin(), s.end());
    
      return (i == s.end() && j == s.end()) || i+1 == j; 
    }
    
    int main()
    {
      assert(check(std::string("")));
      assert(check(std::string("a")));
      assert(check(std::string("abbc")));
      assert(check(std::string("abcdef")));
      assert(check(std::string("abcdee")));
      assert(check(std::string("aaabsdf")));
    
    
      std::cin.unsetf(std::ios::skipws);
      std::istream_iterator<char> i =
        ::adjacent_find(std::istream_iterator<char>(std::cin),
                        std::istream_iterator<char>());
      std::copy(i, std::istream_iterator<char>(),
                std::ostream_iterator<char>(std::cout));
    
      return 0;
    }
    
    
    1. Because of input iterators, we have to return an iterator to the latter one of the two adjacent values.

      The original version of adjacent_find required its value type to be equality comparable. Our new version requires, in addition, the assignable concept.

  3. reverse_word_order

    #include <iostream>
    #include <iterator>
    #include <string>
    #include <list>
    
    template <class BidirectionalIterator, class T,
              class OutputIterator>
    OutputIterator
    reverse_word_order(BidirectionalIterator begin, BidirectionalIterator end,
                       OutputIterator result, const T& separator)
    {
      typedef std::reverse_iterator<BidirectionalIterator> riterator;
    
      riterator rbegin(end);
      riterator rend(begin);
      riterator i;
      while ((i=find(rbegin, rend, separator)) != rend) {
        result = std::copy(i.base(), rbegin.base(), result);
        *result++ = separator;
        rbegin=i;
        ++rbegin;
      }
      result = std::copy(i.base(), rbegin.base(), result);
      return result;
    }
    
    
    int main()
    {
      std::string str("Are these   words?");
    
    // it really works for bidirectional iterators, like std::list<char>::iterator
    //   std::list<char> lista;
    //   std::copy(str.begin(), str.end(), std::back_inserter(lista));
    //   reverse_word_order(lista.begin(), lista.end(),
    // 		     std::ostream_iterator<char>(std::cout, ""), ' ');
    
      std::string str1("a b ");
      std::string str2(" a b");
      std::string str3(" ");
      std::string str4("");
    
      // outputs "words?   these Are"
      std::cout << '"';
      reverse_word_order(str.begin(), str.end(),
    		     std::ostream_iterator<char>(std::cout, ""), ' ');
      std::cout << '"' << std::endl << '"';
    
      // outputs " b a"
      reverse_word_order(str1.begin(), str1.end(),
    		     std::ostream_iterator<char>(std::cout, ""), ' ');
      std::cout << '"' << std::endl << '"';
    
      // outputs "b a "
      reverse_word_order(str2.begin(), str2.end(),
    		     std::ostream_iterator<char>(std::cout, ""), ' ');
      std::cout << '"' << std::endl << '"';
    
      // outputs " "
      reverse_word_order(str3.begin(), str3.end(),
    		     std::ostream_iterator<char>(std::cout, ""), ' ');
      std::cout << '"' << std::endl << '"';
    
      // outputs ""
      reverse_word_order(str4.begin(), str4.end(),
    		     std::ostream_iterator<char>(std::cout, ""), ' ');
      std::cout << '"' << std::endl;
      return 0;
    }
    
    
  4. If we use the ready made algorithms distance and advance, we don't have to care about tag dispatching: the STL does it for us.

    #include <iostream>
    #include <cstring>
    
    template <typename ForwardIter>
    ForwardIter
    mid_point(ForwardIter begin, ForwardIter end)
    {
      ForwardIter i = begin;
      std::advance(i, std::distance(begin, end)/2);
      return i;
    }
    
    int main()
    {
      char* array = "123456789";
      std::cout << *mid_point(array, array+strlen(array)) << std::endl;
      return 0;
    }