STL:

2022-09-26  本文已影响0人  my_passion

<algorithm>

STL 算法的操作参数可以用函数对象, 也可以用函数指针: (模板)函数实参推断可以推断出操作实参的类型

不用记算法有没有 _if 版本, 代码测一下即可, 若有, 把特定元素位置参数换成条件pred即可

迭代器名称

(1) 含 Reslut输出区间 正向 起始位置

(2) 不带迭代器类型标识: 指 inputIterator

1 不改变序列的操作

(1) for_each(first, Last, f)

应用函数(f)到 区间内每个元素

`返回值被忽略`

template<class InputIterator, class Function>
    Function 
for_each(InputIterator first, InputIterator last, Function f)
{
    while (first != last) 
    {
        f(*first);
        ++first;
    }
    return f;      // or, since C++11: return move(f);
}

Note: for_each 的 f 最好不要改 区间元素, 要改则应该用 transform

(2) find(first, last, value) / find_if(first, last, unaPred) / find_if_not(...)

找第1个 符合条件(== / if unaPred(*first) ) / 不符合条件 (if !unaPred(*first) ) 的元素 pos

template<class InputIterator, class T>
    InputIterator 
find (InputIterator first, InputIterator last, const T& val)
{
    while (first!=last) 
    {
        if (*first == val) 
            return first;
        ++first;
    }
    return last;
}

template<class InputIterator, class UnaryPredicate>
    InputIterator 
find_if (InputIterator first, InputIterator last, UnaryPredicate uniPred)
    实现仅1处差别
    `if ( uniPred(*first) )` 

find_if_not
    if ( !uniPred(*first) )

find_first_of(first1, last1, forwardFirst2, forwardLast2, pred)

在序列1中 查找 序列2 任一元素首次 出现(==)/满足条件(if pred(*it, *first1) ) 的 pos

2层循环

template<class InputIterator, class ForwardIterator>
    InputIterator 
find_first_of ( InputIterator first1, InputIterator last1,
                ForwardIterator first2, ForwardIterator last2)
{
    while (first1 != last1) 
    {
        for (ForwardIterator it = first2; it != last2; ++it) 
            if (*it == *first1) // version2: if (pred(*it, *first1) )
                return first1;
                
        ++first1;
    }
    return last1;
}

find_end(forwardFirst1, forwardLast1, forwardFirst2, forwardLast2)

在序列1中 查找 整个 序列2最后1次 出现(==)/满足条件(if pred(*it, *first1) ) 的 pos

2层循环, 要 记录 外层循环 上次匹配查找过程 中 序列1的 起始查找位置

template<class ForwardIterator1, class ForwardIterator2>
    ForwardIterator1 
find_end (ForwardIterator1 first1, ForwardIterator1 last1,
          ForwardIterator2 first2, ForwardIterator2 last2)
{
    if (first2 == last2) 
        return last1; 

    ForwardIterator1 startFindPosInSeq1 = last1; // [1] 外层循环 `上次匹配查找过程` 中 序列1的 `起始查找位置`

    while (first1 != last1)  // [2] `序列1 在外层遍历完`
    {
        ForwardIterator1 it1 = first1;
        ForwardIterator2 it2 = first2;
        
        while (*it1 == *it2) // version2: while (pred(*it1,*it2))
        {    
            ++it1; ++it2;
            if (it2 == last2) // [3] 序列2 遍历完 
            { 
                startFindPosInSeq1 = first1; // [4] 本次查找匹配成功 
                break; 
            }
            
            if (it1 == last1) // [5] `序列1 在内层遍历完`
                return startFindPosInSeq1;
        }
        
        ++first1; // [5] 更新 下次查找匹配 的 起始位置
    }
    return startFindPosInSeq1;
}

adjacent_find(forwardFirst, forwardlast)

第1组 满足条件(== / pred(*first, *next) == true ) 的 相邻元素 pos(前面元素 pos)

template <class ForwardIterator>
    ForwardIterator 
adjacent_find (ForwardIterator first, ForwardIterator last)
{
    if (first != last)
    {
        ForwardIterator next = first; 
        ++next;
        
        while (next != last) 
        {
            if (*first == *next) // version2: if pred(*first, *next)
                return first;
            ++first; ++next;
        }
    }
    return last;
}

(3) count(first, last, value) / count_if(first, last, unaPred)

数 满足条件(== / pred... ) 的 元素个数

template <class InputIterator, class T>
    typename iterator_traits<InputIterator>::difference_type
count (InputIterator first, InputIterator last, const T& val)
{
    typename iterator_traits<InputIterator>::difference_type n = 0;
    while (first!=last) 
    {
        if (*first == val) 
            ++n;
        ++first;
    }
    return n;
}

count_if
    uniPred(*first) 

(4) search(forward1First, forward1Last, forward2First, forward2Last)

在 seq1 中匹配查找 子序列 seq2 出现的 pos, 没找到, 返回 last1

    template<class ForwardIterator1, class ForwardIterator2>
        ForwardIterator1 
    search ( ForwardIterator1 first1, ForwardIterator1 last1,
             ForwardIterator2 first2, ForwardIterator2 last2)
    {
        if (first2==last2) 
            return first1;  // specified in C++11

        while (first1! = last1)   // [1] n(未知)次遍历
        {
            ForwardIterator1 it1 = first1;
            ForwardIterator2 it2 = first2;
            
            while (*it1 == *it2)  // [2] ver2: while (pred(*it1, *it2) )
            {    
                ++it1;            // [3] 双指针联动
                ++it2;
                if (it2 == last2) // [4] 若子序列 seq2 走完
                    return first1;
                    
                if (it1 == last1) // [5] 若母序列 seq1 走完
                    return last1;
            }
            ++first1;             // [4] 母序列 `seq1 下一次匹配查找 起始位置 更新` (子序列 ... 总是为 起始位置)
        }
        return last1;
    }

search_n(forwardFirst, forwardLast, count, value[, binPred] ) // == / pred(*iter, value)

匹配查找 连续 count 个符合条件之元素子序列, 返回子序列 起始迭代器

Note: 外循环内本次匹配失败时, 为提高效率, 下次匹配查找, 直接从当前遍历位置开始, 因为 上次匹配查找 走过的 最多 count 个 elem 其后必然不会出现符合条件的能连续的元素 => 不必从上次匹配查找过程的 下一位置开始

    template<class ForwardIterator, class Size, class T>
        ForwardIterator 
    search_n (ForwardIterator first, ForwardIterator last,
              Size count, const T& val) // version1

    // 2层循环
    外循环
        先 find() 本次匹配查找过程 value 第1次符合条件 pos
        
        leftCount = count - 1
        
        内循环: 最多走 leftCount 步
        
        if 找到剩余leftCount 个 符合条件之元素
            匹配成功 
        else // 本次匹配失败
            更新 下次匹配查找 的起始位置
    匹配失败        
    
    if(count <= 0)
        return last; // 匹配失败
    else
    {
        first = find(fist, last, value); // (1)
        
        while(first != last)             // (2) `Note: 若 本次匹配失败, 则 更新下次匹配查找 的起始位置` 
        {
            Size countLeft = count - 1;
            ForwardIterator cur = first;
            ++cur;
            
            // (3) 3个条件: 区间没遍历完 / 剩余匹配数 != 0 / 元素符合条件
            while(cur != last && countLeft != 0 && *cur == value) 
            {
                ++cur;
                --countLeft;
            }
            
            if(countLeft == 0) // [1] 匹配成功
                return first;
            else               // [2] Note: 本次匹配失败, 为提高效率, `下次匹配查找, 直接从当前遍历位置开始`, 
                first = find(cur, last, value); // 因为 `本次匹配查找 走过的 最多 count 个 elem 其后必然不会出现符合条件的能连续的元素` => `不必从本次匹配查找过程的 下一位置开始`
        }
        return last; // (4) 匹配失败
    }

(5) mismatch(first1, last1, first2)

找2个序列 第1个不匹配 pos, 返回1对(pair)迭代器, 分别指向2序列中 不匹配 pos

Note: 要求 序列2长度 >= 序列1长度, 否则, undefined behavior

template <class InputIterator1, class InputIterator2>
    pair<InputIterator1, InputIterator2>
mismatch (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2 )
{
    while ( first1 != last1 && *first1 == *first2 )  // version2: pred(*first1,*first2)
    { 
        ++first1; 
        ++first2; 
    }
    return std::make_pair(first1,first2);
}

(6) is_permutation(first1, last1, first2)

permutation: 排列

匹配查找 seq1 是否为 seq2 的1个 子排列(元素全匹配, 顺序可不同)

Note: 要求 seq2Len >= seq1Len, 否则, undefined behavior

template <class InputIterator1, class InputIterator2>
    bool
is_permutation(InputIterator1 first1, InputIterator1 last1,
              InputIterator2 first2)
{
    // (1) `mismatch 更新2个区间 起始查找位置` 
    auto iterPair = std::mismatch(first1, last1, first2);
    first1 = iterPair.first;
    first2 = iterPair.second;

    // (2) 若 seq1 先走完, 则 `匹配成功` 
    if (first1 == last1)
        return true;

    // (3) last2 归位 
    InputIterator2 last2 = first2;
    std::advance(last2, std::distance(first1, last1));

    // (4) 遍历 seq1剩余区间, 
    for (InputIterator1 cur1 = first1; cur1!= last1; ++cur1)
    {
        // [1] `当前遍历位置上元素` 在剩余区间 `首次出现` 时
        if (std::find(first1, cur1, *cur1) == cur1)
        {
            // [2] count seq2 中 *cur1 个数, 若 == 0 或 与 seq1 中 *cur 个数不等, 则 `匹配失败` 
            auto n = std::count(first2, last2, *cur1);

            if (n == 0 || std::count(cur1, last1, *cur1) != n)
                return false;
        }
        // else( `非首次出现, 则 略过, 继续向后遍历` )
    }

    // (2) seq1 先走完 => `匹配成功` 
    return true;
}

    // (1)
    struct myClass 
    {           
        void operator() (int i) 
        {
            std::cout << ' ' << i;
        }
    } myObj;
    for_each (vec.begin(), vec.end(), myObj);
    
    // (2)
    auto it = find (vec.begin(), vec.end(), 5);
    if (it != vec.end() )
        std::cout << "found: " << *it << '\n';
        
    bool isOdd (int i) { return i % 2 == 1; }
    auto it = std::find_if (vec.begin(), vec.end(), IsOdd);
    
    // (3)
    std::count_if (vec.begin(), vec.end(), IsOdd);
    
    // (4) 
    // vec = [1, 2, 3, 4, 5, 6], targetArr = [4, 5, 6]
    auto it = std::search (vec.begin(), vec.end(), targetArr, targetArr + 3);
    
    // (5)
    for (int i = 0; i < 3; i++) 
        vec.push_back (i*10); // vec: 10 20 30
    int arr[] = {10,20,80};   // arr: 10 20 80, Note 若 arr = [10, 20] => 结果 undefined behavior
    auto p = std::mismatch (vec.begin(), vec.end(), arr);
    std::cout << *p.first << ", " << *p.second << '\n';
    
    std::cout << std::is_permutation (vec.begin(), vec.end(), arr);

2 改变序列的操作

(1) copy

copy(first, last, outputIterResult)

将区间 [first, last) 所有元素 逐个 复制 到 outputIterFirst 开始的区间

返回 目标区间尾 迭代器

复制操作 无非用 copy ctor 或 copy assignment, copy() 算法用的是 后者

Note: src/dst 区间重叠 & 向后 copy 时, 发生覆盖, 若 srcFirst 距 dstFirst 为 d 个元素 => src 区间以 d 个元素重复

      first     last 
        |       }
        |       |
    1   2   3   4   5   6   7
        |           2|\ 3   4
        | _ _ _ _ _  | 覆盖
         copy      | |
                  \| |
    1   2   3   4   2   3   4

copy() 提高效率的方法: 1个 中间 functor 隔开 2层 特化

(1) 第1层特化 直接用 memmove

(2) 第2层泛化和特化中均用 标签分发 分出普通版和 高效版本 -> 共 3种版本

[1] 每次迭代用 迭代器是否相等(first != last) 决定循环是否继续

[2] ... 用 n = last - first 是否 > 0 ...

[3] memmove

                                                                                                        for(; first != last; ...)
                                                                                                     /      *result = *first;
                                                                                                    /
                                                                                                   / input_iterator_tag 
                                                    泛化      _copy(, iteratorCategory(fitst) )
                                                    <InputIter,              标签分发              \ random_access_iterator_tag
                                                    OutputIter>                                     \ <RAIter, RAIter>
                                                         /                                           \
                                                        /                                                _copy_d(, differencePtrType(first) )
                                                       /                                                    |
                                                      /                                                     |/
                                                     /                                                      for(DifferenceType n = last - first; n > 0; --n, ...)
                                                    /                                                       |\  *result = *first;
            泛化  _copy_dispatch<InputIter,      /                                                        |
                                  OutputIter>()(.)                                                      _copy_d(, (ptrdiff_t*)0 )
        <InputIter,            functorTempObj      |                                                 / 
        OutputIter>                                |                                                / _false_type   
       /                                           | - 特化1  _copy_t(, _type_traits<T>::has_trivial operator= 的临时对象 ) 
      /                                            |  <T*, T*>     |                    标签分发    \ 
copy(.)                                            |               | 实现思路相同                  \ _true_type 
      \                                            | - 特化2  _copy_t()                               memmove 
       \                                              <const T*, T*>                                        
            特化      memmove                                                                             
        (const char*, 
         const char*)
    template<class InputIterator, class OutputIterator>
        OutputIterator 
    copy (InputIterator first, InputIterator last, OutputIterator result)
    {
        while (first != last) 
        {
            *result = *first;
            
            ++result; 
            ++first;
        }
        return result;
    }

copy_backward(biFirst, biLast, biResultLast)

返回 目标区间首 迭代器

template<class BidirectionalIterator1, class BidirectionalIterator2>
    BidirectionalIterator2 
copy_backward ( BidirectionalIterator1 first,
                BidirectionalIterator1 last,
                BidirectionalIterator2 resultLast )
{
    while (last != first) 
        *--resultLast = *--last;
    return resultLast;
}

copy_n(first, n, outputIterResult)

template<class InputIterator, class Size, class OutputIterator>
    OutputIterator 
copy_n (InputIterator first, Size n, OutputIterator result)

copy_if(first, last, outputIterResult, unaPred)

template <class InputIterator, class OutputIterator, class UnaryPredicate>
    OutputIterator 
copy_if (InputIterator first, InputIterator last,
         OutputIterator result, UnaryPredicate pred)
                      
    if ( pred(*first) ) 
    {
        *result = *first;

        ++result;
    }

(2) move

move(first, last, outputIterReslut)

与 copy 区别仅在于 copy 语义换为 move 语义 => 用于 handle 容器, 如 std::vector<std::string>

    template<class InputIterator, class OutputIterator>
        OutputIterator 
    move (InputIterator first, InputIterator last, OutputIterator result)
    {
        while (first!=last) 
        {
            *result = std::move(*first); // move 语义
            
            ++result; 
            ++first;
        }
        return result;
    }

move_backward

(3) fill

fill(forwardFirst, forwardLast, val)

将区间 [first, last) 所有元素 赋值 为 val

template <class ForwardIterator, class T>
    void 
fill (ForwardIterator first, ForwardIterator last, const T& val)
{
    while (first != last) 
    {
        *first = val;
        ++first;
    }
}

fill_n(outputFirst, n, val)

前 n 个元素

template <class OutputIterator, class Size, class T>
    OutputIterator 
fill_n (OutputIterator first, Size n, const T& val)

(4) remove

remove(forwardFirst, forwardLast, value) 移除但不删除

不满足条件( !(*first == value) ) 的 elem 前移 <=> 满足条件(*first == value) 的 elem 后移/移除

返回 不满足条件的 last 位置

value = 1
                      |
    1, 2, 3, 4, 5, 1, |  1, 6, 6
    |\                |  |
    | 覆盖            |  |    残留
    |                 |  |/
    2, 3, 4, 5, 6, 6, |  1, 6, 6
                      |
template <class ForwardIterator, class T>
    ForwardIterator 
remove (ForwardIterator first, ForwardIterator last, const T& val)
{
    ForwardIterator lastPosNotSatisfiedCond = first;
    while (first != last) 
    {
        if ( !(*first == val) )     // (1) 当前遍历元素 不满足条件(!= 指定值) 时, 前移到 不满足条件的第1个位置
        {
            if (lastPosNotSatisfiedCond != first)   
                *lastPosNotSatisfiedCond = *first;
            ++lastPosNotSatisfiedCond;
        }
        ++first;    // (2) `更新 遍历指针`
    }
    return lastPosNotSatisfiedCond;
}

remove_if(forwardFirst, forwardLast, unaPred)

    template <class ForwardIterator, class UnaryPredicate>
        ForwardIterator 
    remove_if (ForwardIterator first, ForwardIterator last,
                UnaryPredicate pred)
                                 
        if ( !uniPred(*first) )

remove_copy(first, last, outputResult, val)

copy 1份到新区间去 remove => 满足条件的(要移除的) 不 copy 到新区间

remove 中 lastPosNotSatisfiedCond 换为 dst 区间 起始迭代器, 去掉 if (lastPosNotSatisfiedCond != first) 条件

template <class InputIterator, class OutputIterator, class T>
        OutputIterator 
    remove_copy (InputIterator first, InputIterator last,
                 OutputIterator result, const T& val)
    {
        while (first != last) 
        {
            if ( !(*first == val) ) 
            {
                *result = *first;
                ++result;
            }
            ++first;
        }
        return result;
    }

remove_copy_if

(5) unique: 类似 remove, 移除但不删除

unique (forwardFirst, forwardLast[, binPred])

移除 相邻重复元素 中第1个之外的元素

重复: == / 满足某条件 pred(*dupFirstPos, *dupOtherPos)

思路: 双指针, 遍历指针 每步都前移, 结果指针在 不满足条件时才前移

Note

[1] 想移除 所有(含不相邻的)重复元素: 先排序, 使所有重复元素相邻; 再 unique()

[2] 尾部 残留元素 可用 erase() 算法去除

[3] 稳定: 保留下来的元素, 原始相对次序不变

    template <class ForwardIterator>
        ForwardIterator 
    unique (ForwardIterator first, ForwardIterator last)
    {
        if (first == last) 
            return last;
        
        first = adjacent_find(first, last); // 找到相邻重复元素的起点
        
        ForwardIterator result = first;
        while (++first != last) // 遍历指针, 结果指针 
        {
            if ( !(*result == *first) )  // ver2: if ( !pred(*result, *first) )
              *(++result) = *first;
        }
        return ++result;
    }

unique_copy(first, last, outputResult)

    template <class InputIterator, class OutputIterator>
        OutputIterator 
    unique_copy (InputIterator first, InputIterator last,
                 OutputIterator result)

(6) transform

transform(inputFirst, inputLast, outputResult, uniOp)

对输入区间上每个元素 用 1元操作, 结果写到 outputReslut 开始的输出区间

transform(inputFirst1, inputLast1, inputFirst2, outputReslut, binOp)

// version 
template <class InputIterator, class OutputIterator, class UnaryOperator>
    OutputIterator 
transform (InputIterator first1, InputIterator last1,
           OutputIterator result, UnaryOperator op)
{
    while (first1 != last1) 
    {
        *result = op(*first1);  // or: *result=binary_op(*first1,*first2++);
        ++result; 
        ++first1;
    }
    return result;
}   

// eg
int op_increase (int i) { return ++i; }

std::vector<int> foo;
std::vector<int> bar;

for (int i = 1; i < 3; i++)
    foo.push_back (i*10);    // foo: 10 20 30

bar.resize(foo.size() );   

std::transform (foo.begin(), foo.end(), bar.begin(), op_increase);  // bar: 11 21 31

(7) swap

swap(a, b)

交换 a, b 的

要求: a/b 必须为 左值, a/b 可以为数组

    template <class T> 
        void 
    swap (T& a, T& b)
    {
        T tmp(std::move(a) ); 
        a = std::move(b); 
        b = std::move(tmp);
    }

    // 数组类型的引用
    template <class T, size_t N> 
        void 
    swap (T (&a)[N], T (&b)[N])
    {
        for (size_t i = 0; i < N; ++i) 
            swap (a[i], b[i]);
    }

swap_ranges(forwardFirst1, forwardLast1, forwardFirst2)

交换2个 区间 中每对元素的值, 循环 + swap (*forwardFirst1, *forwardFirst2)

iter_swap(forwardIter1, forwardIter2)

交换2个 迭代器 所指对象的值

    template <class ForwardIterator1, class ForwardIterator2>
        void 
    iter_swap (ForwardIterator1 forwardIter1, ForwardIterator2 forwardIter2)
    {
      swap (*forwardIter1, *forwardIter2);
    }

(8) replace

replace(forwardFirst, forwardLast, oldValue, newValue)

将区间 [forwardFirst, forwardLast) 中所有等于 oldValue 的 元素 替换为 新值 newValue

    template <class ForwardIterator, class T>
      void 
    replace (ForwardIterator first, ForwardIterator last, 
             const T& old_value, const T& new_value)
    {
        while (first != last) 
        {
            if (*first == old_value) 
                *first = new_value;

            ++first;
        }
    }

replace_if(forwardFirst, forwardLast, unaPred, new_value)

replace_copy(first, last, outputResult, oldValue, newValue)

replace_copy_if(first, last, outputResult, unaPred, newValue)

(9) reverse

reverse(binFirst, binLast)

反转 区间中 元素顺序: 循环 + 双指针 (first, --last) 联动 + iter_swap

    template <class BidirectionalIterator>
        void 
    reverse (BidirectionalIterator first, BidirectionalIterator last)
    {
        while (first != last && first != --last) 
        {
            std::iter_swap (first, last);
            ++first;
        }
    }

reverse_copy(binFirst, binLast, outResult)

(10) rotate

rotate(forwardFirst, forwardMid, forwardLast)

将 [forwardFirst, forwardMid) 与 [forwardMid, forwardLast) 内元素对调

Note: 看似和 swap_ranges() 相近, 实则不同, 前/后者 可以/只能 对调 长度不同/相同的区间

据迭代器类型 分3种实现

[1] 前向

前/后段均设 遍历指针(first / back) 和 哨兵指针(mid / last)

遍历双指针联动

前半段结束, 同时后半段结束
    对调完成, return 

`前/后 半段先结束(但不同时结束)`
    则 `更新 mid = back / back = mid`
    template <class ForwardIterator>
        void 
    rotate (ForwardIterator first, ForwardIterator middle, ForwardIterator last)
    {
        for(ForwardIterator back = middle; ; )
        {
            iter_swap(first, back);
            
            ++first;
            ++back;
            
            if(first == middle) // 前半段先结束
            {
                if(back == last) // 同时后半段结束
                    return;
                mid = back;
            }
            else if(back == last) // 后半段先结束
            {
                back = mid;
            }
        }
    }          

[2] 双向

    前段区间 reverse()
    后段区间 reverse()
    整体   reverse()

[3] 随机: 特殊算法复杂

    first   mid       last
    |       |           |
    |/      |/          |/
    A   B   C   D   E   

    C   D   E   A   B
    

rotate_copy(forwardFirst, forwardMid, forwardLast, outputReslut)

    template <class ForwardIterator, class OutputIterator>
        OutputIterator 
    rotate_copy (ForwardIterator first, ForwardIterator middle,
                 ForwardIterator last, OutputIterator result)
    {
        result = std::copy (middle, last, result);
        return std::copy (first, middle, result);
    }

(11) random_shuffle(raFirst, raLast)

随机重排

3 Partitions 重排

(1) partition(binFirst, binLast, unaPred)

将 [first, last) 中元素 重排, 满足/不满足 条件( pred() == true/false ) 的放 前/后段

返回 满足条件的最后1个元素的 next 位置

思路: 双指针(first / last), 2层循环, 内层2个循环

[1] 循环1: first 从前往后走, 遇到 不满足条件的就停下来

[2] 后指针 last 移到上1个有效位置

[3] 循环2: last 从后往前走, 遇到 满足条件的就停下来

[4] 交换 first, last 所指元素

[5] 更新 前指针 first

Note: 不稳定 ( 原始相对位置 可能变)

    // eg: 满足条件 == elem 为 偶数 

        seq =   0   1   2   3   4   5   6   7   8
                |\                                  |\
                |                                   |
               first                               last
                    
        stop:      first                       last 
        swap:   0   8   2   3   4   5   6   7   1
     first更新:         first         
     
        stop:              first      last 
        swap:   0   8   2   6   4   5   3   7   1
     first更新:                 first
     
                                  last(移到前先检测是否双指针相遇)
        stop:                     first(返回)    
        swap:   0   8   2   6   4   5   3   7   1             
    template <class BidirectionalIterator, class UnaryPredicate>
        BidirectionalIterator 
    partition (BidirectionalIterator first, BidirectionalIterator last, UnaryPredicate pred)
    {
        while(true)
        {
            while(true) // [1]
            {
                if(first == last) // Note: 移到前先检测是否双指针相遇, 相遇则终止
                    return first;
                else if(pred(*first) )
                    ++first;
                else
                    break;
                    
            }
            
            --last; // [2] 因后面要用 pred(*(last)
            
            while(true) // [3]
            {
                if(first == last)
                    return first;
                else if(! pred(*(last) )
                    --last;
                else
                    break;
            }
            
            iter_swap(first, last); // [4]
            
            ++first; // [5]
        }
    }

stable_partition(binFirst, binLast, unaPred)

Note: 保留元素的 原始相对位置 不变

4 排序 sort: 严格弱序比较

[1] 小于比较(LessThan comparable)

5种比较 小于/大于/小于等于/大于等于/等于

等价表示为 1个 基础比较: 小于比较

    大于      x > y   <=>   y < x

    大于等于    x >= y  <=>  !(x < y)

    小于等于    x <= y  <=>  !(y < x)

    等于      !(x < y) && !(y < x)

[2] 严格弱序(strict weak ordering): 定义了 等价 (的条件)

两个元素中 任一个 都不小于/按指定比较规则去比较 都不满足规则的含义 另一个

    !(x < y) && !(y < x) 
    
    广义
        !cmp(x, y) && !cmp(y, x)  

[3] 严格弱序比较 (strick weakly comparable)

满足 小于比较 和 严格弱序 2个条件

反例:cmp 定义为 小于等于

    若 x == y, 则 `按等价定义 !cmp(x, y) && !cmp(y, x)`
    
        => !true && !true => false
        
        `相等, 推导出来的结果却是 不等 => 错误`

(1) sort(raFirst, raLast[, comp])

版本1: 升序 <=> comp == operator <

底层 快排

=> 不稳定 = 不保持原始相对位置

时间复杂度O(nlog(n)).
    bool cmp (int i, int j) { return (i < j); }

    struct Cmp 
    {
        bool operator() (int i, int j) { return (i < j);}
    } cmp;
    
    std::sort (vec.begin(), vec.end(), cmp);  

(2) stable_sort(raFirst, raLast[, comp])

保持原始相对位置

(3) partial_sort(raFirst, raMid, raLast[, comp])

部分排序 [raFirst, raMid) 内排序, 其余无序

(4) nth_element(raFirst, raNth, raLast[, comp])

新区间 nth(第 n+1 个) 元素sort 完整排序结果 nth 元素 值相同, nth 左、右子区间之间 整体有序(< / comp) 但各自内部无序

    std::vector<int> vec{2, 3, 2, 5, 1, 4, 6, 7, 9, 8};

    std::random_shuffle(vec.begin(), vec.end());                // 1 5 7 9 2 4 2 3 6 8

    std::nth_element(vec.begin(), vec.begin() + 3, vec.end()); //  2 1 2 3 4 5 9 7 6 8

5 二分查找

a, b 等价: (!(a < b) && !(b < a)) / (!comp(a, b) && !comp(b, a) )

(1) lower_bound/upper_bound(forwardFirst, forwardLast, value[, comp])

含义: 不破坏排序 下, 可插入 value第1个位置 / 最后1个合适位置 => 等价区间的 前闭端/后开端

实现

二分过程 且 first 指针更新 时, 满足条件

    [1] *mid < value / comp(*mid, value), lower_bound
    
    [2] !(value < *mid) / !comp(value < *mid), upper_bound

最终 可插入 value 的 pos(first)等价于 value 的

    [1] `第1个 位置`                !(*first < value) == *first >= value / !comp(*first, value)
        
        若 `value 存在`, 返回的迭代器 将指向 value 的 `位置`
                  不存在,                             `合适(前插含义)位置`
                  
    [2] `最后1个 合适位置`         value < *first                      / comp(value < *first)
        
        若 value 存在, 返回的迭代器 将指向 value 的 `下一位置`
                 不存在,                           合适(前插含义)位置
    template <class ForwardIterator, class T>
        ForwardIterator 
    lower_bound (ForwardIterator first, ForwardIterator last, const T& val)
    {

        iterator_traits<ForwardIterator>::difference_type len, half;
        
        // (1)
        len = std::distance(first, last);
        
        ForwardIterator mid;
        
        while(len > 0)
        {
            half = len >> 1;
            
            // (2) 取/更新 中间指针
            mid = first;
            std::anvance(mid, half);
            
            if(*mid < value) // comp(*mid, value), [1] 中间位置处比较, 满足条件 
            {
                first = mid; // [2] 更新 遍历指针
                ++first;
                
                len = len - half - 1; // [3] 更新 查找区间长度
            }
            else 
                len = half;
        }
        
        // (3)
        return first;
    }

    template <class ForwardIterator, class T>
        ForwardIterator 
    upper_bound (ForwardIterator first, ForwardIterator last, const T& val)
        
         仅1处不同 if( !(value < *mid ) )

(2) equal_range(forwardFirst, forwardLast, value[, comp])

思路: 先用 lower_bound(first, last, value[, comp]) 找出 等价区间前闭端 firstPos, 再用 upper_bound(firstPos, last, value[, comp]) 找出 等价区间后开端 lastPos

返回 pair(firstPos, lastPos)

    template <class ForwardIterator, class T>
        pair<ForwardIterator,ForwardIterator>
    equal_range (ForwardIterator first, ForwardIterator last, const T& val)
    {
          ForwardIterator firstPos = std::lower_bound (first, last, val);
          
          return std::make_pair ( firstPos, std::upper_bound(firstPos, last, val) );
    }

(3) binary_search(forwardFirst, forwardLast, value[, comp])

查找 [first, last) 是否有 等价于 value 的元素, 返回 true/false

思路: 用 lower_bound 找出 "假设 vlaue 存在的话, 应该出现的位置", 再 比较 该位置上是否为 期望 等价的目标, 并返回 true/false

实现: lower_bound + 是否找到 && !(value < *first)

    template <class ForwardIterator, class T>
        bool 
    binary_search (ForwardIterator first, ForwardIterator last, const T& value)
    {
        first = std::lower_bound(first, last, value); // => !(*first < value)
        
        return (first != last && !(value < *first) );
    }

6 合并: 基于 已排序区间

(1) merge(first1, last1, first2, last2[, comp])

合并2个有序区间为1个新有序区间

稳定

    template <class InputIterator1, class InputIterator2, class OutputIterator>
        OutputIterator 
    merge (InputIterator1 first1, InputIterator1 last1,
           InputIterator2 first2, InputIterator2 last2,
           OutputIterator result)
    {
        // (1) 2个序列都没走完
        while(first1 != last1 && first2 != last2)
        {
            result++ = *first1 < *first2 ? *first1++ : *first2++;
        }
        
        // (2) 至少1个序列走完 => 至少1个 copy 直接返回 第3参数
        return copy(first2, last2, copy(first1, first1, result) );
    }

(2) inplace_merge(biFIrst, biMid, biLast)

将同一序列中 2段连续的有序序列 [first, middle) 和 [middle, last) 合并为1个有序序列 [first, last)

思路: 用 中间缓冲区

    std::inplace_merge (v.begin(), v.begin() + 5, v.end() );

(3) includes(first1, last1, first2, last2)

测试 [first1, last1) 中是否 包含(含子序列) [first2, last2)

(4) 构造 STL set(集合, 并不是 std::set<.>): 无重复, 排序( < / comp)

set_union(first1, last1, first2, last2, outputReslut[, comp])

并集 S1 并 S2

    int first[] = {5,10,15,20,25};
    int second[] = {50,40,30,20,10};
    std::vector<int> v(10);        // 0  0  0  0  0  0  0  0  0  0

    std::sort (first, first+5);     //  5 10 15 20 25
    std::sort (second, second+5);   // 10 20 30 40 50

    std::vector<int>::iterator it = std::set_union (first, first + 5, second, second + 5, v.begin() );
                                               // 5 10 15 20 25 30 40 50  0  0
    v.resize(it-v.begin());                    // 5 10 15 20 25 30 40 50

set_intersection

交集 S1 交 S2

set_difference

差集 S1 - S2: 出现于 S1 但不出现于 S2

set_symmetric_difference

对称差集: (S1 - S2) 并 (S2 - S1)

7 极值

(1) min(a, b[, comp])

    template <class T> 
        const T& 
    min (const T& a, const T& b) 
    {
        return !(b < a) ? a : b;     // !comp(b, a) ? a : b;
    }

max

    template <class T> 
        const T& 
    max (const T& a, const T& b) 
    {
        return (a < b)? b : a;     // comp(a, b)?b:a; 
    }

(2) min_element(forwardFirst, forwardLast[, comp])

返回 区间 [first,last) 中最小元素的迭代器

    ...
    if (*first < *smallest)    // comp(*first, *smallest)
        smallest = first;

max_element

8 其他

(1) lexicographical_compare(first1, last1, first2, last2[, comp])

"字典排列方式" 比较 seq1 = [first1, last1) 与 seq2 = [first2, last2)

seq1, seq2 对应元素逐个比较, 直到

[1] seq1 elem 小 -> return true; else, false -> 继续循环

[2] seq1 先走完(seq1 短) -> return true

[3] seq2 先走完, false

[4] seq1, seq2 同时走完(同长度), return fase

    ...
    return first1 == last1 && first2 != last2;
    
    // (first1 == last1) && (first2 != last2) 
    
    // [2] = true && true == true
    
    // [3] = false && false == false 
    
    // [4] = true && false = false 
    
    // [1] = false && true == seq1 没走完 && seq2 没走完 => 1, 但运行到 return 前, 1已经不可能了

(2) bool next_permutation(biFirst, biLast[, comp])

区间转换下一个(用 < / comp 决定) 排列组合

没有下一个, 推导出第1个( reverse() 即可 ), 返回 fasle

从前到后, 依次固定1个, 然后 变化 其后部分

    3个字符{a b c}的6种排列组合
    
    abc
    acb
    bac
    bca
    cab
    cba

(3) prev_permutation

    #include <iostream>     
    #include <algorithm>

    int main() 
    {
        int arr[] = { 1, 2, 3 };

        std::sort(arr, arr + 3);
        std::reverse(arr, arr + 3);

        std::cout << arr[0] << ' ' << arr[1] << ' ' << arr[2] << '\n';
        while (std::prev_permutation(arr, arr + 3) )
            std::cout << arr[0] << ' ' << arr[1] << ' ' << arr[2] << '\n';

        std::cout << "After loop: " << arr[0] << ' ' << arr[1] << ' ' << arr[2] << '\n';
    }

    // print
    1 2 3
    1 3 2
    2 1 3
    2 3 1
    3 1 2
    3 2 1
    After loop: 1 2 3
上一篇下一篇

猜你喜欢

热点阅读