theArcticOcean

博观而约取,厚积而薄发

C++ 泛型算法学习笔记(equal, accumulate, back_iterator, pair)

equal

equal是区间比较算法
原型为:

template <class _InputIterator1, class _InputIterator2>
inline _LIBCPP_INLINE_VISIBILITY
bool
equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2)
{
    typedef typename iterator_traits<_InputIterator1>::value_type __v1;
    typedef typename iterator_traits<_InputIterator2>::value_type __v2;
    return _VSTD::equal(__first1, __last1, __first2, __equal_to<__v1, __v2>());
}

template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
inline _LIBCPP_INLINE_VISIBILITY
bool
equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred)
{
    for (; __first1 != __last1; ++__first1, (void) ++__first2)
        if (!__pred(*__first1, *__first2))
            return false;
    return true;
}

一般地,我们给equal传入三个参数即可,前两个分别是区间一的left迭代器和right迭代器,最后一个是区间二的left迭代器。从函数原型可以看出,区间二的范围大于等于区间一才有可能得到true。
明白了这层原理,我们可以设计自己的数据类型,并自定义equal,比如:

struct _point{
    int x;
    int y;
    _point():x(0), y(0) {  }
    _point(int x_,int y_):x(x_), y(y_) {  }
    friend _point operator + (const _point p1, const _point p2){
        _point p(p1);
        p.x = p.x + p2.x;
        p.y = p.y + p2.y;
        return p;
    }
    friend ostream& operator << (ostream &out,const _point p){
        out<<"("<<p.x<<" , "<<p.y<<")";
        return out;
    }
    friend bool operator == (const _point &p1, const _point &p2){
        return p1.x == p2.x && p1.y == p2.y;
    }
};

int main()
{
    _point p[] = {{0,0},{1,1},{2,2}};
    cout<<equal(p,p+2,p)<<endl;
    return 0;
}

或者使用lambda表达式定义其他的二元判断符:

    cout<<equal(p+1,p+2,p+2,[](const _point p1,const _point p2){
        return p1.y && p2.y && p1.x/p1.y == p2.x/p2.y;
    })<<endl;

借助equal,我们可以方便的判断回文字符串,比如:

bool isPalindrome(const string str){
    return equal(str.begin(),str.begin()+str.size()/2,str.rbegin());
}

int main()
{
    cout<<isPalindrome("abcba")<<endl;
    cout<<isPalindrome("jordan")<<endl;
    return 0;
}

accumulate

accumulate函数定义在numeric头文件中,用于计算一段范围内的元素之和。
函数原型为:

template <class _InputIterator, class _Tp, class _BinaryOperation>
inline _LIBCPP_INLINE_VISIBILITY
_Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init, _BinaryOperation __binary_op)
{
    for (; __first != __last; ++__first)
        __init = __binary_op(__init, *__first);
    return __init;
}

在不传入第四个参数的情况下,默认是使用二元操作符+。当我我们使用新的二元操作符后,返回值自然受到影响。

struct _point{
    int x;
    int y;
    _point():x(0), y(0) {  }
    _point(int x_,int y_):x(x_), y(y_) {  }
    friend _point operator + (const _point p1, const _point p2){
        _point p(p1);
        p.x = p.x + p2.x;
        p.y = p.y + p2.y;
        return p;
    }
    friend ostream& operator << (ostream &out,const _point p){
        out<<"("<<p.x<<" , "<<p.y<<")";
        return out;
    }
};

int main()
{
    vector<_point> vp;
    vp.push_back(_point(1,1));
    vp.push_back(_point(2,2));
    vp.push_back(_point(3,3));
    cout<<accumulate(vp.begin(),vp.end(),_point(0,0))<<endl;

    cout<<accumulate(vp.begin(),vp.end(),_point(0,0),[](const _point p1, const _point p2){
        _point p(p1);
        p.x = p.x - p2.x;
        p.y = p.y - p2.y;
        return p;
    })<<endl;
    return 0;
}

第二种计算使用了开发者lambda表达式定义的匿名二元函数。
注意:如果直接在结构体中定义operator -,然后再使用:cout<<accumulate(vp.begin(),vp.end(),_point(0,0), -)<<endl;
编译器报错,不认识这样的表达式。

back_iterator

back_iterator返回对象的地址。

template <class _Container>
inline _LIBCPP_INLINE_VISIBILITY
back_insert_iterator<_Container>
back_inserter(_Container& __x)
{
    return back_insert_iterator<_Container>(__x);
}

// ==>

_LIBCPP_INLINE_VISIBILITY explicit back_insert_iterator(_Container& __x) : container(_VSTD::addressof(__x)) {}

// ==>

template <class _Tp>
inline _LIBCPP_NO_CFI _LIBCPP_INLINE_VISIBILITY
_Tp*
addressof(_Tp& __x) _NOEXCEPT
{
  return reinterpret_cast<_Tp *>(
      const_cast<char *>(&reinterpret_cast<const volatile char &>(__x)));
}

// operator = 调用了容器的push_back函数。

_LIBCPP_INLINE_VISIBILITY back_insert_iterator& operator=(const typename _Container::value_type& __value_)
        {container->push_back(__value_); return *this;}

整个过程:back_iterator将容器对象地址转换成back_insert_iterator类的对象指针,通过这个对象指针调用=操作符,就能完成元素的插入。
应用:

    string str;
    str.push_back('1');
    auto it = back_inserter(str);
    *it = '2';
    cout<<str<<endl;  //12

操作符是一个特殊的函数,我们的*it = '2';还可以这样写:*it = (it.operator =('2'));
据此,我们还能将back_iterator和fill_n搭配使用,写出另类的append函数:

    string str;
    str.push_back('1');
    fill_n(back_inserter(str),10,'0');
    cout<<str<<endl;  //10000000000

pair

查看了pair结构体的源码实现C++ pair源码,模拟它写了一个三元组结构体treble:

template<typename T1, typename T2, typename T3>
struct treble {
    T1 first;
    T2 second;
    T3 third;
    treble(): first(),second(),third() {}
    treble(const T1 &__first, const T2 &__second, const T3 &__third){
        first = __first; second = __second; third = __third;
    }
    treble& operator = (const treble &another){
        this->first = another.first;
        this->second = another.second;
        this->third = another.third;
        return *this;
    }
    template <typename T>
    void basic_swap(T &t1, T &t2){
        T t = t1;
        t1 = t2;
        t2 = t;
    }
    void swap(treble &another){
        basic_swap(first,another.first);
        basic_swap(second,another.second);
        basic_swap(third,another.third);
    }
    friend ostream & operator <<(ostream &out, const treble &ins){
        out<<"("<<ins.first<<", "<<ins.second<<", "<<ins.third<<")";
        return out;
    }
};

template<typename T1, typename T2, typename T3>
inline _LIBCPP_INLINE_VISIBILITY
treble<T1,T2,T3>
make_treble(const T1 &__first, const T2 &__second, const T3 &__third)
{
    return treble<T1, T2, T3>(__first, __second, __third);
}

可以测试:

int main()
{
    treble<int,string,double> ins = make_treble(1,string("one"),1.00);
    cout<<ins<<endl;

    treble<int,string,double> ano;
    ano.swap(ins);
    cout<<"after swap:\n";
    cout<<ano<<endl;
    cout<<ins<<endl;
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/theArcticOcean/article/details/79770777
文章标签: C++ template
个人分类: C、C++学习笔记
上一篇algorithm 题集八 (18.03.25)
下一篇QT enVocabulary工程打包问题记录
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭