• C/C++基础---算法概览


    • 符号概念

      1. beg和end表示元素范围的迭代器
      2. beg2表示第二个序列开始位置迭代器,end2表示第二个序列末尾迭代器(如果有)。如没有则假定系列2至少与beg end表示的范围一样大。beg和beg2类型不必匹配,但必须保证两个序列中的元素可以执行特性操作或调用给定的可调用对象。
      3. des表示目的序列的迭代器,目的序列保证有足够的空间存放算法生成的元素。
      4. unaryPred和binaryPred是一元和二元谓词,分别接受来自输入序列的元素,两个谓词都返回可用作条件的类型。
      5. comp是一个二元谓词,满足关联容器中对关键字序的要求
      6. unaryOp和binaryOp是可调用对象,分别使用来自输入序列的一个和两个实参来调用。

    1 查找对象

    在一个输入序列中搜索一个指定值或者一个值的序列
    每个都有两个版本,一个使用底层类型的==来比较;一个使用用户给定的unaryPred和binaryPred比较。

    • 简单查找
    find(beg, end, val);//返回迭代器,指向第一个等于val的元素。未找到,返回end
    find_if(beg, end, unaryPred);//返回迭代器,指向第一个满足unaryPred的元素。未找到,end
    find_if_not(beg, end, unaryPred);//指向第一个不满足unaryPred的元素, 未找到,返回end
    count(beg, end, val);//返回一个计数器,指出val出现了多少次
    count_if(beg, end, unaryPred);//统计有多少个元素满足unaryPred
    all_of(beg, end, unaryPred);
    any_of(beg, end, unaryPred);
    none_of(beg, end, unaryPred);
    上面几个都返回bool值,分别判断是否所有元素满足unaryPred、任一元素满足unaryPred、所有元素都不满足unaryPred。
    如序列为空,any_of返回false,all_of和none_of返回true
    
    • 查找重复值
    下面算法要求前向迭代器,因为有binaryPred了,需要前后两个元素比较,要多遍扫描
    adjacent_find(beg, end);
    adjacent_find(beg, end, binaryPred);
    返回指向第一对相邻重复元素的迭代器。如不存在,返回end
    search_n(beg, end, count, val)
    search_n(beg, end, count, val, binaryPred)
    返回一个迭代器,从此位置开始有count个连续相等元素。如不存在返回end
    
    • 查找子序列
    除了find_first_of之外,都要求两个前向迭代器;find_first_of第一个只需要输入迭代器,第二个序列需要前向迭代器,因为需要支持多次扫描
    search(beg1, end1, beg2, end2)
    search(beg1, end1, beg2, end2, binaryPred)
    返回第二个序列在第一个序列中第一次出现的位置。如未找到,返回end1
    find_first_of(beg1, end1, beg2, end2)
    find_first_of(beg1, end1, beg2, end2, binaryPred)
    返回第一个序列中迭代器,指向序列二中任意一个元素在序列一中首次出现的位置。如未找到,则返回end1
    find_end(beg1, end1, beg2, end2)
    find_end(beg1, end1, beg2, end2, binaryPred)
    类似search,返回最后一次出现的位置。如未找到则返回end1
    

    2 其他只读算法

    要求都是输入迭代器,同样提供两个版本,一个用底层类型的==,一个用用户指定的谓词
    for_each(beg, end, unaryOp):对输入序列中的每个元素应用可调用对象unaryOp。返回值忽略。迭代器支持的话,则可以修改元素。unaryOp大概表示可以传入额外参数吧
    mismatch(beg1, end1, beg2)
    mismatch(beg1, end1, beg2, binaryPred):比较两个序列中的元素,返回一个pair,表示两个序列中第一个不匹配的元素,若均匹配,则pair的first成员为end1,second成员是指向beg2中偏移量等于第一个序列长度的位置。
    equal(beg1, end1, beg2)
    equal(beg1, end1, beg2, binaryPred):确定两个序列是否相等。相等返回true,不相等返回false。
    

    3 二分搜索算法

    要求至少前向迭代器,如果提供随机访问迭代器,性能会好很多。无论什么迭代器都执行对数次比较操作,但是前向迭代器必须花费线性次数的迭代器操作来移动到序列中要比较的元素位置。
    要求序列已经是有序的,行为类似关联容器中的同名成员。返回迭代器,指向给定序列中的正确插入位置—插入后还能保持有序。如比所有元素都大,则返回尾后迭代器。
    每个算法提供两个版本,一个用元素类型的<来检测,一个用comp来检测
    lower_bound(beg, end, val)
    lower_bound(beg, end, val, comp):返回一个迭代器,若val在序列中,则返回val第一次出现的的位置,否则返回第一个插入val不影响原序列顺序的位置
    upper_bound(beg, end, val)
    upper_bound(beg, end, val, comp):返回一个迭代器,若val在序列中,则返回val最后一次出现的位置的下一个位置,否则返回第一个插入val不影响原序列顺序的位置
    equal_bound(beg, end, val)
    equal_bound(beg, end, val, comp):返回一个pair,first成员为lower_bound返回的迭代器,second成员为upper_bound返回的迭代器
    binary_search(beg, end, val)
    binary_search(beg, end, val, comp):返回一个bool值,指出序列中是否含有指定值val。
    备注:二分搜索算法中的comp是一个比较函数,类似于关联容器中关键字类型的比较函数的要求
    

    4 写容器元素的算法

    • 只写不读元素的算法
    要求输出迭代器,表示目的位置,_n版本第二个参数表示写入的元素个数
    fill(beg, end, val)
    fill_n(dest, cnt, val)
    generate(beg, end, Gen)
    generate_n(dest, cnt, Gen):给输入序列的每个元素赋予一个新值。fill将值赋予元素(对于不可拷贝的类型不能用fill),generate执行生成器对象Gen()生成新值。
    
    • 使用输入迭代器的写算法
    读取一个输入序列,将值写入到一个输出序列
    copy(beg, end, dest)
    copy_if(beg, end, dest, unaryPred)
    copy_n(beg, n, dest)
    _if拷贝满足unaryPred的元素,_n拷贝前n个,输入序列至少有n个
    move(beg, end, dest):对输入序列中的每个元素调用std::move,将其移动到迭代器dest开始的序列,没有if和n的版本
    transform(beg, end, dest, unaryOp)
    transform(beg, end, beg2, dest, binaryOp):调用给定操作,将结果写入dest。第一个版本对输入范围中的每个元素应用一元操作,第二个版本对两个输入序列中元素应用二元操作。
    merge(beg1, end1, beg2, end2, dest)
    merge(beg1, end1, beg2, end2, dest, comp):两个输入序列都必须有序,将合并后的序列写入dest中。第一个版本使用<,第二个版本使用给定的操作。
    
    • 使用前向迭代器的写算法
    iter_swap(iter1, iter2):交换iter1和iter2所表示的元素。这两个迭代器可以在同一个容器中,也可以不在同一个容器中。返回void
    swap_ranges(beg1, end1, beg2):输入范围中的所有元素与beg2开始的第二个序列中所有元素进行交换。注意点:两个范围不能重叠。返回递增后的beg2,即最后一个交换元素之后的位置。
    replace(beg, end, old_val, new_val)
    replace(beg, end, unaryPred, new_val):用new_val替换每个匹配元素。第一个版本使用==,第二个版本使用一元谓语unaryPred
    
    • 使用双向迭代器
    算法需要在序列中有反向移动能力
    copy_backward(beg, end, dest) //
    move_backward(beg, end, dest):dest是输出序列的尾后迭代器。输入范围内的元素被拷贝或移动到目的序列的尾元素,然后是倒数第二个,类推。返回从beg拷贝或移动的元素的位置。如范围为空则返回dest
    inplace_merge(beg, mid, end)
    inplace_merge(beg, mid, end, comp):将同一序列的两个有序子序列合并为单一有序序列,并写入原序列。第一个版本使用<,第二个版本使用给定的比较操作。注意点:当序列的顺序和给定的比较操作不符的时候将出错。
    

    划分与排序

    每个都提供了稳定和不稳定版本。稳定版本保证保持相等元素的相对顺序。由于稳定算法会做更多的工作,可能比不稳定版本慢得多并消耗更多内存。

    • 划分算法
    要求双向迭代器,划分为满足和不满足两部分
    is_partitioned(beg, end, unaryPred):如果所有满足谓词unaryPred的元素都在不满足unaryPred的元素之前则返回true(序列为空也返回true),否则返回flase
    partition_copy(beg, end, dest1, dest2, unaryPred):将满足unaryPred的元素拷贝到dest1,将不满足unaryPred的元素拷贝到dest2。返回一个pair,分别保存两个输出序列的被拷贝的元素的末尾。输入序列与两个目的序列不能重叠。
    partition_point(beg, end, unaryPred):输入序列必须是用unaryPred划分过的,返回满足unaryPred的范围的尾后迭代器。
    stable_partition(beg, end, unaryPred)
    partition(beg, end, unaryPred):使用unaryPred划分输入序列,满足unaryPred的元素放在序列开始,不满足unaryPred的元素放在序列尾部,返回一个迭代器,指向最后一个满足unaryPred的元素之后的元素,若所有元素均不满足unaryPred则返回beg
    
    • 排序算法
    要求随机访问迭代器。两个版本,一个用元素的<比较,一个用comp比较
    partial_sort和nth_element只进行部分排序,速度比整体排序算法更快。
    素,另一个版本接受一个额外的参数来指定排序关系:
    sort(beg, end)
    stable_sort(beg, end)
    sort(beg, end, comp)
    stable_sort(beg, end, comp)
    排序整个范围
    
    is_sorted(beg, end)
    is_sorted(beg, end, comp)
    返回一个bool值,指出整个输入序列是否有序
    
    is_sorted_until(beg, end)
    is_sorted_until(beg, end, comp)
    //查找最长初始有序子序列,返回子序列尾后迭代器
    
    partial_sort(beg, mid, end)
    partial_sort(beg, mid, end, comp)
    排序mid-beg个元素。排序后,从beg到mid中的元素都是有序的,mid到end中的元素顺序未指定。
    
    partial_sort_copy(beg, end, destBeg, destEnd)
    partial_sort_copy(beg, end, destBeg, destEnd, comp)
    排序输入范围内的元素,并将足够多的元素拷贝到destBeg和destEnd所指示的序列中。如果目的序列大于等于输入范围则排序整个输入序列并存入输出序列,若目的序列小于输入范围,则拷贝输入序列中与目的范围一样多的元素。
    返回一个迭代器,指向目的范围中已排序部分的尾后迭代器。如目的序列小于等于输入范围,则返回destEnd(此时是否整个输入序列排序???)。
    
    nth_element(beg, nth, end),只需要确定第n个
    nth_element(beg, nth, end, comp):参数nth是一个指向输入序列的一个迭代器。执行此函数后,序列中的元素都会按照比较操作定义的顺序围绕nth所指的元素进行划分。
    

    6 通用重排操作

    重排输入序列中元素的顺序。remove和unique会重排使得第一部分满足某种标准。返回一个迭代器标记子序列的末尾。其他算法,如reverse、rotate和random_shuffle都重排整个序列。
    基本版本在原序列内部进行重排,_copy版本写入到指定目标序列中。

    • 使用前向迭代器的重排序列
    remove(beg, end, val)
    remove_if(beg, end, unaryPred)
    remove_copy(beg, end, dest, val)
    remove_copy_if(beg, end, dest, unaryPred)
    从序列中删除元素,采用的办法是:用保留的元素覆盖要删除的元素。算法返回一个迭代器,指向最后一个保留元素的尾后位置。
    
    unique(beg, end)
    unique(beg, end, binaryPred)
    unique_copy(beg, end, dest)
    unique_copy(beg, end, dest, binaryPred)
    重排序列,对于相邻的满足条件的元素,通过覆盖来进行删除,返回一个迭代器,指向最后一个保留元素的尾后位置。
    
    rotate(beg, mid, end)
    rotate_copy(beg, mid, end, dest)
    围绕mid指向的元素进行元素转动。元素mid成为首元素,随后是mid+1->end之间的之前的元素,再接着是beg到mid之前的元素。返回一个迭代器,指向原来beg位置的元素。
    
    • 使用双向迭代器的重排算法
    reverse(beg, end)
    reverse_copy(beg, end, dest)
    翻转序列中的元素。reverse返回void,reverse_copy返回一个迭代器,指向拷贝到目的序列的元素的尾后位置。
    
    • 使用随机访问迭代器的重排算法
    random_shuffle(beg, end)使用默认的随机数生成器,如rand()
    random_shuffle(beg, end, rand)使用指定的随机数生成器
    shuffle(beg, end, Uniform_rand)使用随机数引擎,可参考<random>头文件
    第二个版本接收一个可调用对象参数,该对象必须接收一个difference_type类型参数n,并生成0到此值区间内的一个服从均匀分布的随机整数[0, n)。shuffle第三个参数须满足均匀分布随机数生成器的要求。所有版本都返回void
    default_random_engine defaultEngine;    // default engine.
    shuffle(a.begin(), a.end(), defaultEngine);
    // 使用系统时钟作为种子
    unsigned seed = chrono::system_clock::now().time_since_epoch().count();
    shuffle(a.begin(), a.end(), default_random_engine(seed));
    
    // 自定义的generator, 用来random_shuffle.
    class SelfGenerator
    {
    public:
        ptrdiff_t operator() (ptrdiff_t max)
        {
            double temp;
            temp = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
            return static_cast<ptrdiff_t>(temp * max);
        }
    };
    array<int, 10> a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    printContainer(a, "a: ");
    SelfGenerator sg;
    random_shuffle(a.begin(), a.end(), sg);
    printContainer(a, "a: ");
    自定义的generator比调用rand()要好,是一个对象,内部封装了自己的状态,不像rand()用一个静态变量保存其状态。rand这样天生线程不安全,无法同时有两个互不干扰的随机数流。
    shuffle时间复杂度O(n)。算法内部进行n-1次交换。
    

    7 排列算法

    生成序列的字典序排列中的下一个或前一个,返回要给bool指出是否还有下一个或前一个
    abc、acb、bac、bca、cab、cba
    这些算法假定序列中的元素都是唯一的。要求双向迭代器。
    is_permutation(beg1, end1, beg2)
    is_permutation(beg1, end1, beg2, binaryPred)
    判断两个序列是否为同一元素集的不同排列。序列二只看前end1-beg1个元素。不同元素类型如int和double也可以一样。
    next_permutation(beg, end)
    next_permutation(beg, end, comp):如果序列已经是最后一个排序,则本函数将序列重排为最小的序列,返回false。否则将输入序列转为字典序的下一个排列,返回true。
    prev_permutation(beg, end)
    prev_permutation(beg, end, comp):若序列已经是第一个排序,则本函数将序列重排为最大的序列,返回false。否则将序列转为字典序的上一个排序,返回true。
    

    8 有序序列的集合算法

    实现了有序序列上的一般集合操作,要求输入迭代器。
    includes(beg, end, beg2, end2)
    includes(beg, end, beg2, end2, comp):如果第二个序列中的每个元素都包含在输入序列中则返回true(这里使用的是==),否则返回false。第一个版本使用<指示元素为升序,第二个版本使用comp来确定元素的顺序(<和comp仅确定容器的元素顺序)。
    set_union(beg1, end1, beg2, end2, dest)
    set_union(beg1, end1, beg2, end2, dest, comp)
    对两个序列中的所有元素,创建它们的有序序列,输出合集。输出序列保存在dest中。
    set_intersection(beg1, end1, beg2, end2, dest)
    set_intersection(beg1, end1, beg2, end2, dest, comp)
    对两个输入序列中均包含的元素创建它们的有序序列,输出交集。保存在dest中。
    set_difference(beg1, end1, beg2, end2, dest)
    set_difference(beg1, end1, beg2, end2, dest, comp)
    对出现在第一个序列但不出现在第二个序列中的元素创建一个有序序列
    set_symmetric_difference(beg1, end1, beg2, end2, dest)
    set_symmetric_difference(beg1, end1, beg2, end2, dest, comp)
    对只出现在一个序列中的元素,创建一个有序序列,保存在dest中。合集的补集
    

    9 最大值和最小值

    第一组对值进行操作,第二组接收一个序列,要求输入迭代器。
    min(val1, val2)
    min(val1, val2, comp)
    min(init_list)
    min(init_list, comp)
    max(val1, val2)
    max(val1, val2, comp)
    max(init_list)
    max(init_list, comp)
    返回val1和val2中最小值/最大值,或initializer_list中最小值/最大值
    实参类型必须完全一致,参数和返回类型都是const引用
    minmax(val1, val2)
    minmax(val1, val2, comp)
    minmax(init_list)
    minmax(init_list, comp)
    返回一个pair,分别表示最小值和最大值
    min_element(beg, end)
    min_element(beg, end, comp):返回给定序列中的最小值
    max_element(beg, end)
    max_element(beg, end, comp):返回给定序列中的最大值
    minmax_element(beg, end)
    minmax_element(beg, end, comp):返回一个pair,分别表示最小元素和最大元素
    
    • 字典序比较
    根据第一对不相等的元素的相对大小来返回结果。两个序列都要求输入迭代器
    lexicographical_compare(beg1, end1, beg2, end2)
    lexicographical_compare(beg1, end1, beg2, end2, comp)
    如果第一个序列在字典序中小于第二个序列,则返回true,否则返回false。
    

    10 数值算法

    <numeric>头文件 要求输入迭代器,如输出数据,目的位置要求输出迭代器
    accumulate(beg, end, init)
    accumulate(beg, end, init, binaryOp)
    返回输入序列所有值的和。和的初始值由init指定。返回类型和init的类型相同。第一个版本使用+,第二个版本使用binaryOp。
    inner_product(beg1, end1, beg2, init)  
    inner_product(beg1, end1, beg2, init, binOp1, binOp2)
    返回两个序列的内积。和的初始值由init指定,返回类型和init相同。第一个版本使用* +,第二个版本使用binOp1,binOp2。
    partial_sum(beg, end, dest)
    partial_sum(beg, end, dest, binaryOp)
    将新序列写入dest,每个新元素的值都等于输入范围中当前位置和之前位置上所有元素之和。第一个版本使用+,第二个版本使用binaryOp
    adjacent_difference(beg, end, dest)
    adjacent_difference(beg, end, dest, binaryOp)
    将新序列写入dest,每个新元素(除了首元素)的值都为输入范围中当前位置和前一个位置元素之差。第一个版本使用-,第二个版本使用binaryOp。
    iota(beg, end, val)
    将val赋予首元素,并将递增后的值赋予下一元素,直至结束。val可以是一个字面值常量。
    
  • 相关阅读:
    PHP多进程(四) 内部多进程
    STL map and multimap
    Understanding Function Objects
    Working with Bit Flags Using STL
    STL Algorithms
    STL set and multiset
    Understanding Smart Pointers
    More Effective C++ 学习笔记(1)
    Adaptive Container: stack and queue
    第一个 Python 程序
  • 原文地址:https://www.cnblogs.com/logchen/p/10188354.html
Copyright © 2020-2023  润新知