zoukankan      html  css  js  c++  java
  • 剩下5种算法代码分析与使用示例(remove 、rotate 、sort、lower_bound、accumulate)

    一、移除性算法 (remove)

     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
     
    // TEMPLATE FUNCTION remove_copy
    template < class _InIt,
             class _OutIt,
             class _Ty > inline
    _OutIt _Remove_copy(_InIt _First, _InIt _Last,
                        _OutIt _Dest, const _Ty &_Val, _Range_checked_iterator_tag)
    {
        // copy omitting each matching _Val
        _DEBUG_RANGE(_First, _Last);
        _DEBUG_POINTER(_Dest);
        for (; _First != _Last; ++_First)
            if (!(*_First == _Val))
                *_Dest++ = *_First;
        return (_Dest);
    }


    template < class _InIt,
             class _OutIt,
             class _Ty > inline
    _OutIt unchecked_remove_copy(_InIt _First, _InIt _Last,
                                 _OutIt _Dest, const _Ty &_Val)
    {
        // copy omitting each matching _Val
        return _STD _Remove_copy(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Dest, _Val,
                                 _STD _Range_checked_iterator_tag());
    }


    // TEMPLATE FUNCTION remove
    template < class _FwdIt,
             class _Ty > inline
    _FwdIt remove(_FwdIt _First, _FwdIt _Last, const _Ty &_Val)
    {
        // remove each matching _Val
        _First = find(_First, _Last, _Val);
        if (_First == _Last)
            return (_First);    // empty sequence, all done
        else
        {
            // nonempty sequence, worth doing
            _FwdIt _First1 = _First;
            return (_STDEXT unchecked_remove_copy(++_First1, _Last, _First, _Val));
        }
    }

    如下图所示:


    假设现在想要remove 的元素是3,则传入到 

    接着遍历First ~ Last 区间的元素,将非移除元素拷贝到前面,覆盖前面的元素,最后的指向如图,函数返回的是Dest 位置,如下代

    码所示:

    for (; _First != _Last; ++_First)

    if (!(*_First == _Val))


                *_Dest++ = *_First;

    由上图可看出移除性算法并没有改变元素的个数,如果要真正删除,可以将remove 的返回值传入erase 进行删除,如:

    v.erase(remove(v.begin(), v.end(), 3), v.end()); 即会将后面两个元素4 和 5 删除掉。

    在这里顺便提一下,erase 会使当前迭代器失效,但可以返回下一个迭代器,故如果需要在遍历中删除,下面的做法才是正确的:

     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
     
    #include <iostream>
    #include <vector>

    using namespace std;

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

        //for (vector<int>::iterator it=v.begin(); it!=v.end(); ++it)
        //{
        //  if (*it == 3)
        //      v.erase(it);          ERROR!
        //  else
        //      cout<<*it<<' ';
        //}

        for (vector<int>::iterator it = v.begin(); it != v.end();)
        {
            if (*it == 3)
                it = v.erase(it);
            else
            {
                cout << *it << ' ';
                ++it;
            }
        }

        cout << endl;
        return 0;
    }

    示例代码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
     
    #include <iostream>
    #include <vector>
    #include <list>
    #include <algorithm>
    using namespace std;

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


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

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

        /*remove(v.begin(), v.end(), 3);
        for_each(v.begin(), v.end(), print_element);
        cout<<endl;*/

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

        return 0;
    }


    二、变序性算法( rotate)

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
     
    template<class _FwdIt> inline
    void rotate(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last)
    {
        // rotate [_First, _Last)
        if (_First != _Mid && _Mid != _Last)
            _Rotate(_CHECKED_BASE(_First), _CHECKED_BASE(_Mid), _CHECKED_BASE(_Last), _Iter_cat(_First));
    }

    rotate 调用了_Rotate,实际上_Rotate 继续调用了某个函数,内部实现代码比较长,而且不容易看懂,这边可以看一下简易的等价

    版本实现,来自这里,如下:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    template <class ForwardIterator>
    void rotate (ForwardIterator first, ForwardIterator middle,
                 ForwardIterator last)
    {
        ForwardIterator next = middle;
        while (first != next)
        {
            swap (*first++, *next++);
            if (next == last) next = middle;
            else if (first == middle) middle = next;
        }
    }


    假设一个容器有 1 2 3 4 5 6 六个元素,现在想把 1 2 放到后面去,可以这样写 rotate(v.begin(), v.begin()+2, v.end());  如下图所示:


    即将first 与 next 对应的元素互换且不断向前推进,直到first == next 为止。


    三、排序算法 (sort)

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    template<class _RanIt> inline
    void sort(_RanIt _First, _RanIt _Last)
    {
        // order [_First, _Last), using operator<
        _DEBUG_RANGE(_First, _Last);
        std::_Sort(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Last - _First);
    }

    template < class _RanIt,
             class _Pr > inline
    void sort(_RanIt _First, _RanIt _Last, _Pr _Pred)
    {
        // order [_First, _Last), using _Pred
        _DEBUG_RANGE(_First, _Last);
        _DEBUG_POINTER(_Pred);
        std::_Sort(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Last - _First, _Pred);
    }


    sort 重载了两个版本,第一个版本只有2个参数,默认按从小到大排序(using operator<);第二个版本有三个参数,即可以自定义比较逻辑

    (_Pred)。它们都用了标准库的std::_Sort, 跟踪进去发现比较复杂,在_Sort 内会根据一些条件选择不同的排序方式,如标准库的堆排序,合并

    序,插入排序等。站在使用的角度看,没必要去深究,但如果是想学习相关的排序,那是很好的资源。

    示例代码2:

     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
     
    #include <iostream>
    #include <vector>
    #include <list>
    #include <algorithm>
    using namespace std;

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

    bool my_greater(int a, int b)
    {
        return a > b;
    }

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

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

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

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

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

        return 0;
    }

    此外,sort 有个坑,如果你自己传递比较逻辑,需要注意,如下:



    四、已序区间算法 (lower_bound 、upper_bound)

    使用这些算法的前提是区间已经是有序的。

     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
     
    // TEMPLATE FUNCTION lower_bound
    template < class _FwdIt,
             class _Ty,
             class _Diff > inline
    _FwdIt _Lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty &_Val, _Diff *)
    {
        // find first element not before _Val, using operator<
        _DEBUG_ORDER_SINGLE(_First, _Last, true);
        _Diff _Count = 0;
        _Distance(_First, _Last, _Count);

        for (; 0 < _Count; )
        {
            // divide and conquer, find half that contains answer
            _Diff _Count2 = _Count / 2;
            _FwdIt _Mid = _First;
            std::advance(_Mid, _Count2);
            _DEBUG_ORDER_SINGLE(_Mid, _Last, false);

            if (_DEBUG_LT(*_Mid, _Val))
                _First = ++_Mid, _Count -= _Count2 + 1;
            else
                _Count = _Count2;
        }
        return (_First);
    }

    template < class _FwdIt,
             class _Ty > inline
    _FwdIt lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty &_Val)
    {
        // find first element not before _Val, using operator<
        _ASSIGN_FROM_BASE(_First,
                          _Lower_bound(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Val, _Dist_type(_First)));
        return _First;
    }


    lower_bound() 返回第一个“大于等于给定值" 的元素位置,其实还重载了另一个low_bound 版本,如下:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
     
    // TEMPLATE FUNCTION lower_bound WITH PRED
    template < class _FwdIt,
             class _Ty,
             class _Diff,
             class _Pr > inline
    _FwdIt _Lower_bound(_FwdIt _First, _FwdIt _Last,
                        const _Ty &_Val, _Pr _Pred, _Diff *)

    也就是可以自定义比较逻辑,需要注意的是如果使用这个版本,那么区间应该本来就是按comp 方法排序的,如下面这句话:

    The elements are compared using operator< for the first version, and comp for the second. The elements in the range shall already

     be sorted according to this same criterion (operator< or comp), or at least partitioned with respect to val.

    由于是已序区间,所以函数内用的是二分查找,而两个版本主要的代码不同在于:
    _DEBUG_LT(*_Mid, _Val)

    _DEBUG_LT_PRED(_Pred, *_Mid, _Val)

    upper_bound 与 lower_bound 类似,不过返回的是第一个”大于给定值“ 的元素位置。

    示例代码3:

     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
     
    #include <iostream>
    #include <vector>
    #include <list>
    #include <algorithm>
    using namespace std;

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


    int main(void)
    {
        int a[] = { 1, 10, 10, 14, 15, 16 };
        vector<int> v(a, a + 6);

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

        vector<int>::iterator it;
        it = lower_bound(v.begin(), v.end(), 10);
        if (it != v.end())
        {
            cout << it - v.begin() << endl;
        }

        it = upper_bound(v.begin(), v.end(), 10);
        if (it != v.end())
        {
            cout << it - v.begin() << endl;
        }

        return 0;
    }


    五、数值算法(accumulate)

     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
     
    // TEMPLATE FUNCTION accumulate
    template < class _InIt,
             class _Ty > inline
    _Ty _Accumulate(_InIt _First, _InIt _Last, _Ty _Val)
    {
        // return sum of _Val and all in [_First, _Last)
        _DEBUG_RANGE(_First, _Last);
        for (; _First != _Last; ++_First)
            _Val = _Val + *_First;
        return (_Val);
    }

    template < class _InIt,
             class _Ty > inline
    _Ty accumulate(_InIt _First, _InIt _Last, _Ty _Val)
    {
        // return sum of _Val and all in [_First, _Last)
        return _Accumulate(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Val);
    }

    // TEMPLATE FUNCTION accumulate WITH BINOP
    template < class _InIt,
             class _Ty,
             class _Fn2 > inline
    _Ty _Accumulate(_InIt _First, _InIt _Last, _Ty _Val, _Fn2 _Func)
    {
        // return sum of _Val and all in [_First, _Last), using _Func
        _DEBUG_RANGE(_First, _Last);
        _DEBUG_POINTER(_Func);
        for (; _First != _Last; ++_First)
            _Val = _Func(_Val, *_First);
        return (_Val);
    }

    template < class _InIt,
             class _Ty,
             class _Fn2 > inline
    _Ty accumulate(_InIt _First, _InIt _Last, _Ty _Val, _Fn2 _Func)
    {
        // return sum of _Val and all in [_First, _Last), using _Func
        return _Accumulate(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Val, _Func);
    }

    accumulate 重载了两个版本,第一个版本实现的是累加,第二个版本带_Func 参数,可以自定义计算,比如累乘等。代码都比较好理解,就不赘述

    了。看下面的示例代码4:

     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
     
    #include <iostream>
    #include <vector>
    #include <list>
    #include <algorithm>
    #include <numeric>
    using namespace std;

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

    int mult(int a, int b)
    {
        return a * b;
    }

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

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

        // 累加
        cout << accumulate(v.begin(), v.end(), 0) << endl;

        // 累乘
        cout << accumulate(v.begin(), v.end(), 1, mult) << endl;

        return 0;
    }

    参考:

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

    转载于:https://www.cnblogs.com/alantu2018/p/8471431.html

  • 相关阅读:
    ES6 -- (1) 简介、let、块级作用域、const、顶层对象的属性、globalThis对象
    TS -- (5)声明合并、代码检查
    TS -- (4)类、类与接口、泛型
    TS -- (3)声明文件、内置对象、类型别名、字符串字面量类型、元组、枚举
    TS -- (2)接口、数组的类型、函数的类型
    TS -- (1)环境,快速入门,基础类型,类型断言、变量声明、解构、展开
    css的三定位方式的区别
    Array循环
    scroll操作
    【Nodejs】记一次图像识别的冒险
  • 原文地址:https://www.cnblogs.com/twodog/p/12137463.html
Copyright © 2011-2022 走看看