• 非变动性算法源代码分析与使用示例( for_each、min_element 、find_if、search 等)


    非变动性算法代码分析与示例:

    一、for_each

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    // TEMPLATE FUNCTION for_each
    template < class _InIt,
             class _Fn1 > inline
    _Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func)
    {
        // perform function for each element
        _DEBUG_RANGE(_First, _Last);
        _DEBUG_POINTER(_Func);
        _CHECKED_BASE_TYPE(_InIt) _ChkFirst(_CHECKED_BASE(_First));
        _CHECKED_BASE_TYPE(_InIt) _ChkLast(_CHECKED_BASE(_Last));
        for (; _ChkFirst != _ChkLast; ++_ChkFirst)
            _Func(*_ChkFirst);
        return (_Func);
    }

    函数以模板实现,_Inlt 即 iterator 类型,_Fn1 是函数指针,函数体内首先判断迭代器是否在范围内以及传递的第三个参数是否是函

    指针,接下去两行实际上就是定义两个临时的迭代器,相当于 _Inlt  ChkFirst(_First); 在遍历的过程中将每个容器元素取出并当作参

    递给函数指针,即 _Func(*ChkFirst);  for_each 函数返回值是函数指针


    二、max_element、min_element

    两个函数实现差不多,只看min_element:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     

    // TEMPLATE FUNCTION min_element
    template<class _FwdIt> inline
    _FwdIt _Min_element(_FwdIt _First, _FwdIt _Last)
    {
        // find smallest element, using operator<
        _DEBUG_RANGE(_First, _Last);
        _FwdIt _Found = _First;
        if (_First != _Last)
            for (; ++_First != _Last; )
                if (_DEBUG_LT(*_First, *_Found))
                    _Found = _First;
        return (_Found);
    }

    template<class _FwdIt> inline
    _FwdIt min_element(_FwdIt _First, _FwdIt _Last)
    {
        // find smallest element, using operator<
        _ASSIGN_FROM_BASE(_First,
                          _Min_element(_CHECKED_BASE(_First), _CHECKED_BASE(_Last)));
        return (_First);
    }

    首先  #define _ASSIGN_FROM_BASE(_Dest, _Src)  _Dest = (_Src) 即将_Min_element 函数的返回值复制给_First,而在

    _Min_element 函数内就是遍历容器,不断保存最小元素的位置,其中 #define _DEBUG_LT(x, y) ((x) < (y))   故

    _DEBUG_LT(*_First, *_Found) 也就是取出元素比较大小,返回最后保存的最小元素位置。

    实际上min_element 还重载了另一个函数模板:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    template < class _FwdIt,
             class _Pr > inline
    _FwdIt _Min_element(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
    {
        // find smallest element, using _Pred
        _DEBUG_RANGE(_First, _Last);
        _DEBUG_POINTER(_Pred);
        _FwdIt _Found = _First;
        if (_First != _Last)
            for (; ++_First != _Last; )
                if (_DEBUG_LT_PRED(_Pred, *_First, *_Found))
                    _Found = _First;
        return (_Found);
    }

    template < class _FwdIt,
             class _Pr > inline
    _FwdIt min_element(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
    {
        // find smallest element, using _Pred
        _ASSIGN_FROM_BASE(_First,
                          _Min_element(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Pred));
        return (_First);
    }

    主要的区别只是在于这个版本可以自定义进行比较,比如如果容器内不是装着数值元素,而是string 或者其他类型,也许它们没有重

    载 operator<,可以自定义一个函数对它们进行比较大小,如 #define _DEBUG_LT_PRED(pred, x, y) pred(x, y) 就是这个意思。


    三、find、find_if

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    // TEMPLATE FUNCTION find
    template<class _InIt, class _Ty>
    inline
    _InIt _Find(_InIt _First, _InIt _Last, const _Ty &_Val)
    {
        // find first matching _Val
        _DEBUG_RANGE(_First, _Last);
        for (; _First != _Last; ++_First)
            if (*_First == _Val)
                break;
        return (_First);
    }

    template<class _InIt, class _Ty>
    inline
    _InIt find(_InIt _First, _InIt _Last, const _Ty &_Val)
    {
        // find first matching _Val
        _ASSIGN_FROM_BASE(_First,
                          _Find(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Val));
        return (_First);
    }

    // TEMPLATE FUNCTION find_if
    template < class _InIt,
             class _Pr > inline
    _InIt _Find_if(_InIt _First, _InIt _Last, _Pr _Pred)
    {
        // find first satisfying _Pred
        _DEBUG_RANGE(_First, _Last);
        _DEBUG_POINTER(_Pred);
        for (; _First != _Last; ++_First)
            if (_Pred(*_First))
                break;
        return (_First);
    }

    template < class _InIt,
             class _Pr > inline
    _InIt find_if(_InIt _First, _InIt _Last, _Pr _Pred)
    {
        // find first satisfying _Pred
        _ASSIGN_FROM_BASE(_First,
                          _Find_if(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Pred));
        return (_First);
    }

    里面很多宏跟前面函数出现的是一样的,find 就是遍历容器,找出与Val 相等的第一个元素位置,函数返回迭代器 。

    find_if 则可以自定义查找,不一定是与某值相等,也可以其他比较如大于小于等,如if (_Pred(*_First))  如果_Pred 函数返回为真

    则break,至于_Pred 怎样实现就不关find_if 的事了。

    示例代码1:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
     
    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;

    void print_element(int n)
    {
        cout << n << ' ';
    }

    bool greater_than_3(int n)
    {
        return n > 3;
    }

    int main(void)
    {
        int a[] = { 1, 2, 3, 4, 5 };
        vector<int> v(a, a + 5);

        vector<int>::const_iterator it;
        for (it = v.begin(); it != v.end(); ++it)
            cout << *it << ' ';
        cout << endl;

        for_each(v.begin(), v.end(), print_element);
        cout << endl;

        for (it = v.begin(); it != v.end(); ++it)
            cout << *it << ' ';
        cout << endl;

        it = min_element(v.begin(), v.end());
        if (it != v.end())
        {
            cout << *it << endl;
        }

        it = max_element(v.begin(), v.end());
        if (it != v.end())
        {
            cout << *it << endl;
        }

        it = find(v.begin(), v.end(), 3);
        if (it != v.end())
        {
            cout << it - v.begin() << endl;
        }
        else
            cout << "not found" << endl;

        it = find_if(v.begin(), v.end(), greater_than_3);
        if (it != v.end())
        {
            cout << it - v.begin() << endl;
        }
        else
            cout << "not found" << endl;

        return 0;
    }
     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    // TEMPLATE FUNCTION search
    template < class _FwdIt1,
             class _FwdIt2,
             class _Diff1,
             class _Diff2 > inline
    _FwdIt1 _Search(_FwdIt1 _First1, _FwdIt1 _Last1,
                    _FwdIt2 _First2, _FwdIt2 _Last2, _Diff1 *, _Diff2 *)
    {
        // find first [_First2, _Last2) match
        _DEBUG_RANGE(_First1, _Last1);
        _DEBUG_RANGE(_First2, _Last2);
        _Diff1 _Count1 = 0;
        _Distance(_First1, _Last1, _Count1);
        _Diff2 _Count2 = 0;
        _Distance(_First2, _Last2, _Count2);

        for (; _Count2 <= _Count1; ++_First1, --_Count1)
        {
            // room for match, try it
            _FwdIt1 _Mid1 = _First1;
            for (_FwdIt2 _Mid2 = _First2; ; ++_Mid1, ++_Mid2)
                if (_Mid2 == _Last2)
                    return (_First1);
                else if (!(*_Mid1 == *_Mid2))
                    break;
        }
        return (_Last1);
    }

    template < class _FwdIt1,
             class _FwdIt2 > inline
    _FwdIt1 search(_FwdIt1 _First1, _FwdIt1 _Last1,
                   _FwdIt2 _First2, _FwdIt2 _Last2)
    {
        // find first [_First2, _Last2) match
        _ASSIGN_FROM_BASE(_First1,
                          _Search(_CHECKED_BASE(_First1), _CHECKED_BASE(_Last1),
                                  _CHECKED_BASE(_First2), _CHECKED_BASE(_Last2),
                                  _Dist_type(_First1), _Dist_type(_First2)));
        return _First1;
    }

    函数传入4个迭代器,假设前两个迭代器指示的位置有10个元素,后两个迭代器指示的位置有2个元素,如果在第一个区间能够找到

    完全匹配第二个区间的元素,则返回起始位置,如果不能则返回Last1,即第一个区间末尾,注意必须顺序匹配2个元素,也可以看

    成在第一个区间寻找第一次出现的第二个区间子段。

    函数的实现也不难理解,双重循环,比如首先比较L1[0] 与 L2[0] , 如果相等再比较L1[1] 与 L2[1]; 如果不等则移动,从L1[1] 开始比

    较,假设L1[4], L1[5] 与L2[0], L2[1] 完全匹配,则返回值是指向L1[4] 的 iterator。

    此外seach 也重载了另一个版本,可以自定义比较,代码比较长且跟上面重复较多就不贴了,主要的变化就是将上面24行的代码

    换成 else if (!_Pred(*_Mid1, *_Mid2)) 也就是自定义比较逻辑。


    下面贴一个MSDN 的例子:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
     
    // alg_search.cpp
    // compile with: /EHsc
    #include <vector>
    #include <list>
    #include <algorithm>
    #include <iostream>

    // Return whether second element is twice the first
    bool twice (int elem1, int elem2 )
    {
        return 2 * elem1 == elem2;
    }

    int main( )
    {
        using namespace std;
        vector <int> v1, v2;
        list <int> L1;
        vector <int>::iterator Iter1, Iter2;
        list <int>::iterator L1_Iter, L1_inIter;

        int i;
        for ( i = 0 ; i <= 5 ; i++ )
        {
            v1.push_back( 5 * i );
        }
        for ( i = 0 ; i <= 5 ; i++ )
        {
            v1.push_back( 5 * i );
        }

        int ii;
        for ( ii = 4 ; ii <= 5 ; ii++ )
        {
            L1.push_back( 5 * ii );
        }

        int iii;
        for ( iii = 2 ; iii <= 4 ; iii++ )
        {
            v2.push_back( 10 * iii );
        }

        cout << "Vector v1 = ( " ;
        for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ )
            cout << *Iter1 << " ";
        cout << ")" << endl;

        cout << "List L1 = ( " ;
        for ( L1_Iter = L1.begin( ) ; L1_Iter != L1.end( ) ; L1_Iter++ )
            cout << *L1_Iter << " ";
        cout << ")" << endl;

        cout << "Vector v2 = ( " ;
        for ( Iter2 = v2.begin( ) ; Iter2 != v2.end( ) ; Iter2++ )
            cout << *Iter2 << " ";
        cout << ")" << endl;

        // Searching v1 for first match to L1 under identity
        vector <int>::iterator result1;
        result1 = search (v1.begin( ), v1.end( ), L1.begin( ), L1.end( ) );

        if ( result1 == v1.end( ) )
            cout << "There is no match of L1 in v1."
                 << endl;
        else
            cout << "There is at least one match of L1 in v1"
                 << "  and the first one begins at "
                 << "position " << result1 - v1.begin( ) << "." << endl;

        // Searching v1 for a match to v2 under the binary predicate twice
        vector <int>::iterator result2;
        result2 = search  (v1.begin( ), v1.end( ), v2.begin( ), v2.end( ), twice );

        if ( result2 == v1.end( ) )
            cout << "There is no match of L1 in v1."
                 << endl;
        else
            cout << "There is a sequence of elements in v1 that "
                 << "are equivalent  to those in v2 under the binary "
                 << "predicate twice  and the first one begins at position "
                 << result2 - v1.begin( ) << "." << endl;
    }

    /*
    Vector v1 = ( 0 5 10 15 20 25 0 5 10 15 20 25 )
    List L1 = ( 20 25 )
    Vector v2 = ( 20 30 40 )
    There is at least one match of L1 in v1
    and the first one begins at position 4.
    There is a sequence of elements in v1 that are equivalent
    to those in v2 under the binary predicate twice
    and the first one begins at position 2.
    */

    参考:

    C++ primer 第四版
    Effective C++ 3rd
    C++编程规范

  • 相关阅读:
    判断二叉树是否BST
    树基础训练(一)
    Trie 简介
    二叉树的一些补充
    红黑树
    平衡二叉树(AVL)介绍及其实现
    二叉查找树(BST)的实现
    二叉树基本知识
    微信小程序提示框
    urllib3使用指南
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8471418.html
Copyright © 2020-2023  润新知