zoukankan      html  css  js  c++  java
  • C++STL算法分析之:非变易算法

     

    最近看了stl源码剖析和分析,不禁感慨,stl真是数学和计算机科学结合的奇葩!精妙的组合构成了强大的stl,虽然在某些对数据结构和算法要求非常高的情况下(比如ACM)stl可能不如其他,但是在大型应用和程序中stl已经做得足够完美了。

    我将会在文章中分析stl每个算法的源码及其分析,更本质的stl构建思想建议大家看看侯捷大师的《stl源码剖析》吧。
    现在我们来看看stl算法中的非易变算法,其他算法比如排序算法、易变算法我会以后添加上,stl中的非易变算法有:for_each(),find(),find_if(),adjacent_find(),find_first_of(),count(),count_if(),mismatch(),equal(),search(),search_n(),find_end().我会结合其源码来分析,应用的话只要把源码看明白了,就不难了。这个版本的stl是SGI STL,大家注意。


    for_each()
    它用来遍历一个序列中的元素,对指定序列中的每一个元素执行所定义的function操作,源码如下:
    template <class _InputIter, class _Function>
    _Function for_each(_InputIter __first, _InputIter __last, _Function __f) {
    __STL_REQUIRES(_InputIter, _InputIterator);
    for ( ; __first != __last; ++__first)
    __f(*__first);
    return __f;
    }
    算法很简单,要注意他返回的是__f,所以你可以这样用他:
    struct print{
    int count;
    print(){count=0;}
    void operator()(int x)
    { /* function*/;}
    };
    print p = for_each(lt.begin(),lt.end(),print());


    find()
    find用来查找指定序列中是否存在某个元素__val,并返回迭代器位置(如果不存在,返回end()),源码如下:
    template <class _InputIter, class _Tp>
    inline _InputIter find(_InputIter __first, _InputIter __last,
    const _Tp& __val,
    input_iterator_tag)
    {
    while (__first != __last && !(*__first == __val))
    ++__first;
    return __first;
    }


    find_if()
    弄清楚find()的实现原理,就不难理解find_if(),这个函数返回使定义的函数__pred为真时迭代器的位置,同样如果全为假,则返回end(),源码如下:
    template <class _InputIter, class _Predicate>
    inline _InputIter find_if(_InputIter __first, _InputIter __last,
    _Predicate __pred,
    input_iterator_tag)
    {
    while (__first != __last && !__pred(*__first))
    ++__first;
    return __first;
    }


    adjacent_find()
    这个函数用来查找指定序列中是否有两个连续的元素相等(或使__pred为真),并返回迭代器的位置,注意是返回第一个元素的位置,如果没有,则返回end().函数有两个形式,分别是相等和谓词判断,源码如下:
    /* 没有谓词判断,即只判断相等否*/
    template <class _ForwardIter>
    _ForwardIter adjacent_find(_ForwardIter __first, _ForwardIter __last) {
    __STL_REQUIRES(_ForwardIter, _ForwardIterator);
    __STL_REQUIRES(typename iterator_traits<_ForwardIter>::value_type,
    _EqualityComparable);
    if (__first == __last)
    return __last;
    _ForwardIter __next = __first;
    while(++__next != __last) {
    if (*__first == *__next)
    return __first;
    __first = __next;
    }
    return __last;
    }
    /*有谓词判断,是否满足__pred*/
    template <class _ForwardIter, class _BinaryPredicate>
    _ForwardIter adjacent_find(_ForwardIter __first, _ForwardIter __last,
    _BinaryPredicate __binary_pred) {
    __STL_REQUIRES(_ForwardIter, _ForwardIterator);
    __STL_BINARY_FUNCTION_CHECK(_BinaryPredicate, bool,
    typename iterator_traits<_ForwardIter>::value_type,
    typename iterator_traits<_ForwardIter>::value_type);
    if (__first == __last)
    return __last;
    _ForwardIter __next = __first;
    while(++__next != __last) {
    if (__binary_pred(*__first, *__next))
    return __first;
    __first = __next;
    }
    return __last;
    }
    谓词判断注意:__pred函数是需要两个参数的。


    find_first_of()
    此函数用于查找指定序列中的元素是否存在一个元素,也在另一个序列元素中(就是查找是否存在交集),或是否各有一元素满足指定函数__comp,源码如下:
    // find_first_of, with and without an explicitly supplied comparison function.

    template <class _InputIter, class _ForwardIter>
    _InputIter find_first_of(_InputIter __first1, _InputIter __last1,
    _ForwardIter __first2, _ForwardIter __last2)
    {
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_REQUIRES(_ForwardIter, _ForwardIterator);
    __STL_REQUIRES_BINARY_OP(_OP_EQUAL, bool,
    typename iterator_traits<_InputIter>::value_type,
    typename iterator_traits<_ForwardIter>::value_type);

    for ( ; __first1 != __last1; ++__first1)
    for (_ForwardIter __iter = __first2; __iter != __last2; ++__iter)
    if (*__first1 == *__iter)
    return __first1;
    return __last1;
    }

    template <class _InputIter, class _ForwardIter, class _BinaryPredicate>
    _InputIter find_first_of(_InputIter __first1, _InputIter __last1,
    _ForwardIter __first2, _ForwardIter __last2,
    _BinaryPredicate __comp)
    {
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_REQUIRES(_ForwardIter, _ForwardIterator);
    __STL_BINARY_FUNCTION_CHECK(_BinaryPredicate, bool,
    typename iterator_traits<_InputIter>::value_type,
    typename iterator_traits<_ForwardIter>::value_type);

    for ( ; __first1 != __last1; ++__first1)
    for (_ForwardIter __iter = __first2; __iter != __last2; ++__iter)
    if (__comp(*__first1, *__iter))
    return __first1;
    return __last1;
    }


    count():
    此函数用于计算某个元素在指定序列中出现的次数,此函数有两种形式,第二种是把指定的n以引用的方式传进去,从而得出n。源码不难,很好理解,如下:
    /*这个是传应用n,是没有返回值的*/
    template <class _InputIter, class _Tp, class _Size>
    void count(_InputIter __first, _InputIter __last, const _Tp& __value,
    _Size& __n) {
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_REQUIRES(typename iterator_traits<_InputIter>::value_type,
    _EqualityComparable);
    __STL_REQUIRES(_Tp, _EqualityComparable);
    for ( ; __first != __last; ++__first)
    if (*__first == __value)
    ++__n;
    }
    /*这个只有三个参数,是有N作为返回值的*/
    template <class _InputIter, class _Tp>
    typename iterator_traits<_InputIter>::difference_type
    count(_InputIter __first, _InputIter __last, const _Tp& __value) {
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_REQUIRES(typename iterator_traits<_InputIter>::value_type,
    _EqualityComparable);
    __STL_REQUIRES(_Tp, _EqualityComparable);
    typename iterator_traits<_InputIter>::difference_type __n = 0;
    for ( ; __first != __last; ++__first)
    if (*__first == __value)
    ++__n;
    return __n;
    }
    注意:使用的时候一定要区分返回值!!传引用是没有返回值的!!!


    count_if():
    和count()一样,只不过是多了一个谓词判断,查找的是满足谓词判断__pred的值的个数,源码如下:
    /*引用,没有返回值*/
    template <class _InputIter, class _Predicate, class _Size>
    void count_if(_InputIter __first, _InputIter __last, _Predicate __pred,
    _Size& __n) {
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_UNARY_FUNCTION_CHECK(_Predicate, bool,
    typename iterator_traits<_InputIter>::value_type);
    for ( ; __first != __last; ++__first)
    if (__pred(*__first))
    ++__n;
    }
    /*有返回值*/
    template <class _InputIter, class _Predicate>
    typename iterator_traits<_InputIter>::difference_type
    count_if(_InputIter __first, _InputIter __last, _Predicate __pred) {
    __STL_REQUIRES(_InputIter, _InputIterator);
    __STL_UNARY_FUNCTION_CHECK(_Predicate, bool,
    typename iterator_traits<_InputIter>::value_type);
    typename iterator_traits<_InputIter>::difference_type __n = 0;
    for ( ; __first != __last; ++__first)
    if (__pred(*__first))
    ++__n;
    return __n;
    }
    使用时同样要注意返回值的问题。


    mismatch()
    此函数用于找出指定序列中首个不等于另一个序列(或首个使谓词判断为假)的元素的位置,注意是返回的两个地址。 因为这部分源码又丢失,故先空着吧。。


    equal()
    和mismatch函数一样,不过他返回的是bool值,false和true。


    search():
    此函数在一个指定的序列中匹配另一个序列,有两种形式,同上,有一种是谓词判断的:源码如下:
    template <class _ForwardIter1, class _ForwardIter2>
    _ForwardIter1 search(_ForwardIter1 __first1, _ForwardIter1 __last1,
    _ForwardIter2 __first2, _ForwardIter2 __last2)
    {
    __STL_REQUIRES(_ForwardIter1, _ForwardIterator);
    __STL_REQUIRES(_ForwardIter2, _ForwardIterator);
    __STL_REQUIRES_BINARY_OP(_OP_EQUAL, bool,
    typename iterator_traits<_ForwardIter1>::value_type,
    typename iterator_traits<_ForwardIter2>::value_type);

    // Test for empty ranges
    if (__first1 == __last1 || __first2 == __last2)
    return __first1;

    // Test for a pattern of length 1.
    _ForwardIter2 __tmp(__first2);
    ++__tmp;
    if (__tmp == __last2)
    return find(__first1, __last1, *__first2);

    // General case.

    _ForwardIter2 __p1, __p;

    __p1 = __first2; ++__p1;

    _ForwardIter1 __current = __first1;

    while (__first1 != __last1) {
    __first1 = find(__first1, __last1, *__first2);
    if (__first1 == __last1)
    return __last1;

    __p = __p1;
    __current = __first1;
    if (++__current == __last1)
    return __last1;

    while (*__current == *__p) {
    if (++__p == __last2)
    return __first1;
    if (++__current == __last1)
    return __last1;
    }

    ++__first1;
    }
    return __first1;
    }

    template <class _ForwardIter1, class _ForwardIter2, class _BinaryPred>
    _ForwardIter1 search(_ForwardIter1 __first1, _ForwardIter1 __last1,
    _ForwardIter2 __first2, _ForwardIter2 __last2,
    _BinaryPred __predicate)
    {
    __STL_REQUIRES(_ForwardIter1, _ForwardIterator);
    __STL_REQUIRES(_ForwardIter2, _ForwardIterator);
    __STL_BINARY_FUNCTION_CHECK(_BinaryPred, bool,
    typename iterator_traits<_ForwardIter1>::value_type,
    typename iterator_traits<_ForwardIter2>::value_type);

    // Test for empty ranges
    if (__first1 == __last1 || __first2 == __last2)
    return __first1;

    // Test for a pattern of length 1.
    _ForwardIter2 __tmp(__first2);
    ++__tmp;
    if (__tmp == __last2) {
    while (__first1 != __last1 && !__predicate(*__first1, *__first2))
    ++__first1;
    return __first1;   
    }

    // General case.

    _ForwardIter2 __p1, __p;

    __p1 = __first2; ++__p1;

    _ForwardIter1 __current = __first1;

    while (__first1 != __last1) {
    while (__first1 != __last1) {
    if (__predicate(*__first1, *__first2))
    break;
    ++__first1;
    }
    while (__first1 != __last1 && !__predicate(*__first1, *__first2))
    ++__first1;
    if (__first1 == __last1)
    return __last1;

    __p = __p1;
    __current = __first1;
    if (++__current == __last1) return __last1;

    while (__predicate(*__current, *__p)) {
    if (++__p == __last2)
    return __first1;
    if (++__current == __last1)
    return __last1;
    }

    ++__first1;
    }
    return __first1;
    }
    源码有点长,不过大体结构已经相当明白了,仔细理解就会懂。


    search_n():
    他所做的工作是在指定序列中查找是否有n个连续元素与给定元素相等(或使得谓词判断为真),使用时要注意参数顺序,源码余下:

    template <class _ForwardIter, class _Integer, class _Tp>
    _ForwardIter search_n(_ForwardIter __first, _ForwardIter __last,
    _Integer __count, const _Tp& __val) {
    __STL_REQUIRES(_ForwardIter, _ForwardIterator);
    __STL_REQUIRES(typename iterator_traits<_ForwardIter>::value_type,
    _EqualityComparable);
    __STL_REQUIRES(_Tp, _EqualityComparable);

    if (__count <= 0)
    return __first;
    else {
    __first = find(__first, __last, __val);
    while (__first != __last) {
    _Integer __n = __count - 1;
    _ForwardIter __i = __first;
    ++__i;
    while (__i != __last && __n != 0 && *__i == __val) {
    ++__i;
    --__n;
    }
    if (__n == 0)
    return __first;
    else
    __first = find(__i, __last, __val);
    }
    return __last;
    }
    }

    template <class _ForwardIter, class _Integer, class _Tp, class _BinaryPred>
    _ForwardIter search_n(_ForwardIter __first, _ForwardIter __last,
    _Integer __count, const _Tp& __val,
    _BinaryPred __binary_pred) {
    __STL_REQUIRES(_ForwardIter, _ForwardIterator);
    __STL_BINARY_FUNCTION_CHECK(_BinaryPred, bool,
    typename iterator_traits<_ForwardIter>::value_type, _Tp);
    if (__count <= 0)
    return __first;
    else {
    while (__first != __last) {
    if (__binary_pred(*__first, __val))
    break;
    ++__first;
    }
    while (__first != __last) {
    _Integer __n = __count - 1;
    _ForwardIter __i = __first;
    ++__i;
    while (__i != __last && __n != 0 && __binary_pred(*__i, __val)) {
    ++__i;
    --__n;
    }
    if (__n == 0)
    return __first;
    else {
    while (__i != __last) {
    if (__binary_pred(*__i, __val))
    break;
    ++__i;
    }
    __first = __i;
    }
    }
    return __last;
    }
    }


    find_end():
    此函数用于找出在一个指定序列中另一个序列的最后一个匹配序列的位置,如果没有则返回last(end()),仍然是有两种形式,现只给出一种
    即可

    template <class _ForwardIter1, class _ForwardIter2>
    _ForwardIter1 __find_end(_ForwardIter1 __first1, _ForwardIter1 __last1,
    _ForwardIter2 __first2, _ForwardIter2 __last2,
    forward_iterator_tag, forward_iterator_tag)
    {
    if (__first2 == __last2)
    return __last1;
    else {
    _ForwardIter1 __result
    = __last1;
    while (1) {
    _ForwardIter1 __new_result
    = search(__first1, __last1, __first2, __last2);
    if (__new_result == __last1)
    return __result;
    else {
    __result
    = __new_result;
    __first1
    = __new_result;
    ++__first1;
    }
    }
    }
  • 相关阅读:
    IE浏览器版本的判断
    Ajax中的同步和异步
    linq之多表连接
    C#中const 和 readonly 修饰符的用法详解
    sql中的分页实现
    JS中的编码,解码类型及说明
    HttpContext概念讲解
    VS语法书写提示
    c#版本23个设计模式
    批处理 使用默认浏览器 打开html文件
  • 原文地址:https://www.cnblogs.com/lvpengms/p/1662833.html
Copyright © 2011-2022 走看看