C++之泛型算法


我们承担ROS,FastDDS等通信中间件,C++,cmake等技术的项目开发和专业指导和培训,有10年+相关工作经验,质量有保证,如有需要请私信联系。

概述

  • 大多数算法在头文件algorithm中,在头文件numeric中定义了一组数值泛型算法。理解算法最基本的方法就是了解他们是否读取元素,改变元素,或是重排元素顺序
  • 使用STL算法经常需要使用函数对象和函数适配器,所以需要#include
  • 所有算法都被设计用来处理一个或多个iterator区间,所以,迭代器令算法不依赖于容器,但算法依赖于元素类型的操作,如find算法依赖元素"==“运算符,其他算法可能要求元素支持”<"运算符。这也意味着如果想让自定义类型支持算法,需要自定义运算符泛型算法只作用于迭代器上而不会执行容器上的操作,带来了一个特性:算法永远不会改变容器的大小
  • 插入迭代器:back_inserter/front_inserter/inserter
  • STL算法命名时引入了两个后缀:
    1. 后缀_if:要求有函数或函数对象作为参数
    2. 后缀_copy:此算法表示元素不只被操作,还会被复制到标的区间

for_each()

常用指数:*****
C++11之后范围for循环提供了更大的方便

  • UnaryProc for_each(beg, end, UnaryProc op)
    • 对区间[beg, end)的每一个元素调用op(elem)
    • 返回op的一个拷贝,在C++11中返回的op是移动过的
    • op可以改动元素,但它的任何返回值都会被忽略

非更易型算法

不会改变元素值和元素次序

元素计数

count/count_if

difference_type count(beg, end, const T& value)/difference_type count_if(beg, end, op)

  • 第一形式计算[beg, end)中元素值等于value的元素个数,第二形式计算[beg, end)中令op(elem)结果为true的元素个数
  • 返回类型difference_type,用来表示iterator间距的类型
  • 注意:op不应该在函数调用过程中改变状态

最大值和最小值

min_element/max_element

ForwardIterator min_element(beg, end)/min_element(beg, end, op)/max_element(beg, end)/max_element(beg, end, op)/pair<ForwardIterator,ForwardIterator> minmax_element(beg,end)/pair<ForwardIterator,ForwardIterator> minmax_element(beg, end, op)

  • 这6个算法分别返回(beg, end]中最小元素位置,最大元素位置,最小和最大组成的pair
  • 无op版本的将以operator<进行比较
  • op用来比较两个元素,op(elem1, elem2),如果elem1<elem2应返回true
  • 如果存在多个最小值和最大值,min_element和max_element返回找到的第一个目标元素,minmax_element返回第一个最小元素和最后一个最大元素,所以max_element和minmax_element返回的最大元素不是同一个

查找元素

find/find_if

  • 查找第一个匹配元素:InputIterator find(beg, end, const T& value)/find_if(beg, end, op)/find_if_not(beg, end, op)
    • 第一形式返回[beg, end)中第一个元素值等于value的元素位置,第二形式返回[beg, end)中第一个op(elem)为true的元素;第三形式(始自C++11)返回op(true)为false的元素
    • 如果没有找到,返回end
    • op不应该在函数调用过程中改变状态
    • 如果是已排序区间,使用已排序区间的算法更有效
  • 查询前n个连续匹配值:ForwardIterator search_n(beg, end, count, const T& value)/search_n(beg, end, const T& value, op)
    • 第一形式返回[beg, end)中连续count个元素值都等于value的第一个元素位置;第二形式返回[beg, end)中连续count个元素造成op(elem, value)返回为true的第一个元素的位置,如果没有找到返回end
    • 注意,op不应在调用过程中改变状态
  • 查找第一个子区间:ForwardIterator search(beg, end, searchBeg, searchEnd)/search(beg, end, searchBeg, searchEnd, op)
    • 两种形式都返回[beg, end)内与[searchBeg, searchEnd)吻合的第一个子区间内的第一元素位置;第一种形式中,子区间内的元素必须完全等于[searchBeg,searchEnd)内的元素;第二种形式中,子区间内的元素和[searchBeg, searchEnd)对应元素必须op(elem, searchElem)为true;如果没有找到,两种形式都返回end
  • 查找最后一个子区间:ForwardIterator find_end(beg, end, searchBeg, searchEnd)/find_end(beg, end, searchBeg, searchEnd, op):同上一个的区别是,返回最后一个匹配的子区间的第一元素位置
  • 查找某些元素的第一次出现的地点:InputIterator find_first_of(beg, end, searchBeg, searchEnd)/find_first_of(beg, end, searchBeg, searchEnd, op)
    • 第一个形式返回第一个出现于[beg,end)和[searchBeg, searchEnd)的元素的位置;第二形式返回[beg,end)区间中第一个满足以下条件的元素:它和[searchBeg, searchEnd)内的每个元素进行op(elem, searchElem)的结果都是true;没有找到则返回end
  • 查找两个连续且相等的元素:ForwardIterator adjacent_find(beg, end)/adjacent_find(beg, end, op)
    • 第一个形式返回第一对连续两个相等元素中的第一元素位置;第二形式返回[beg, end)内第一对op(elem, nextElem)为true的元素;如果没有找到则返回end

区间的比较

equal

检验相等性:bool equal(beg, end, cmpBeg)/equal(beg, end, cmpBeg, op)

  • 第一形式判断[beg, end)区间的元素是否都和以cmpBeg开头的区间内的元素相等;第二形式判断[beg, end)区间的元素和以cmpBeg开头的区间对应的元素是否能够在调用op(elem, cmpElem)后返回true
  • 必须确保以cmpBeg开头的区间包含足够元素

is_permutation

测试不定序的相等性(C++11):bool is_permutation(beg1, end1, beg2)/is_permutation(beg1, end1, beg2, op)

  • 两种形式都检测[beg1, end1)区间的元素是否和beg2起始之区间元素在顺序无所谓的情况下相等
  • 第一种形式以operator==比较,第二种形式使用predicate op(elem1,elem2)比较,应该在elem1与elem2相等时返回true
  • 注意:所有的迭代器必须要有相等的值类型

mismatch

查找第一处不同:pair<InputIterator1, InputIterator2> mismatch(beg, end, cmpBeg)/mismatch(beg, end, cmpBeg, op)

  • 第一形式返回[beg, end)区间

检验区间

用以检验区间:始自C++11,用来检验某个给定区间是否符合某条件

is_sorted/is_sorted_until

检验是否排序:bool is_sorted(beg, end) / bool is_sorted(beg, end, op) / ForwardIterator is_sorted_until(beg, end) / ForwardIterator is_sorted_until(beg, end, op)

  • is_sorted检验区间内的元素是否已经排序;is_sorted_until返回[beg, end)内第一个破坏排序的元素
  • 第一和第三使用operator<比较元素,第二和第四使用op(elem1, elem2),如果elem1小于elem2返回true
  • 如果区间为空返回true,如果只有一个元素返回end

op

检验是否被分割:使用op(elem1, elem2),elem1小于elem2时返回true

  • bool is_partitioned(beg, end, op)
    • 判断符合op的元素是否被置于所有不符合的元素之前
  • ForwardIterator partition_point(beg, end, op)
    • 如果区间为空,partition_point返回end
  • 检验是否形成Heap

更易型算法

  • 有两种方法可以更易:写算法要求:原序列必须不小于要求算法写入的元素数目
    • 运用迭代器遍历序列
    • 将元素从源区间复制到目标区间

复制元素

  • OutputIterator copy(sourceBeg, sourceEnd, destBeg):destBeg不能在[sourceBeg, sourceEnd)之间(常用指数:*****)
  • OutputIterator copy_if(sourceBeg, sourceEnd, destBeg, op):源区间和目标区间不可重叠
  • OutputIterator copy_n(sourceBeg, Size num, destBeg)
  • BidirectionalIterator2 copy_backward(BidirectionalIterator1 sourceBeg, BidirectionalIterator1 sourceEnd, BidirectionalIterator2 destEnd):destEnd不可处于(sourceBeg, sourceEnd]区间
    • 上述四个算法都将源区间[sourceBeg, sourceEnd)中的所有元素复制到以destBeg为起点或以destEnd为终点的目标区间
    • 返回目标区间内最后一个被复制元素的下一个位置

搬移元素

  • OutputIterator move(InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg)
  • BidirectionalIterator2 move_backward(BidirectionalIterator1 sourceBeg, BidirectionalIterator1 sourceEnd, BidirectionalIterator2 destBeg)

转换和结合元素

  • OutIter transform(InIter beg, InIter end, OutIter destBeg, op):将源区间的元素转换到目标区间
  • OutIter transform(InIter beg, InIter end, Initer sourceBeg, InputIter sourceEnd, op):将两个源序列中的元素合并后写到目标区间

移除算法

移除某些元素

移除序列内的元素

  • 函数:
    • ForwardIterator remove(ForwardIterator beg, ForwardIterator end, const T& value):移除区间内与value相等的元素
    • ForwardIterator remove_if(ForwardIterator beg, ForwardIterator end, op):移除区间中每个令op(elem)为true的元素
      • 返回最后一个未被移除元素的下一位置
      • 会把原本置于后面的未移除元素向前移动,覆盖被移除元素
      • 无法删除元素,也不会改变元素状态

排序算法:

1.对所有元素排序:
• sort(first, end)/sort(first, end, op):对区间[first, end)进行排序,第一形式使用operator<排序,第二形式使用op(elem1, elem2)进行排序(如果是string,首字母按字典顺序进行排列)
• stable_sort:与sort的区别是,能保证相等元素的相对位置不变。前两个参数接收表示范围的迭代器,第三个参数为可调用表达式表示重新排序的条件
注意:以上四个算法需要随即访问迭代器,所以只能用于vector,string,deque和数组,所以不能用于关联容器;list有自己的sort成员函数
2.局部排序:
• partial_sort(first, sort_end, end)/partial_sort(first, sort_end, end, op):第一形式以operator<对[beg, end)区间内的元素进行排序,使[first, sort_end)区间内的元素处于已序状态;第二形式使用二元谓词排序
○ 与sort不同的是partial_sort并不对所有元素排序,一旦[first, sort_end)之间的之间的所有元素都排序好就立马停止;
○ 如果sort_end等于end则对所有序列进行排序
• partial_sort_copy(first, end, destfirst, destend):copy和partion_sort的结合,将元素从源区间[first, end)复制到[destfirst, destend)并进行排序,
○ 被排序和复制的元素是源和目标两者所含元素量的较小值
○ 两者都返回目标区间内最后一个被复制元素的下一个位置
○ 如果源区间小于目标区间,所有元素都会被排序
• partition:接受两个表示序列的迭代器,第三个参数为谓词,使得谓词为true的排在序列前半部分,谓词为false的排在序列的后半部分,算法返回一个迭代器,指向最后一个使谓词为true的元素后面的位置
• 该算法只需要双向迭代器,因此可以在任何标准序列迭代器上使用partition和stable_partition
3.根据第n个元素排序:
• nth_element(first, biu, end)/nth_element(first, biu, end, func):排序后,第biu位置前的元素小于biu位置的元素,第biu位置后的元素大于biu位置的元素
5.partition:接受两个表示序列的迭代器,第三个参数为谓词,使得谓词为true的排在序列前半部分,谓词为false的排在序列的后半部分
算法返回一个迭代器,指向最后一个使谓词为true的元素后面的位置
该算法只需要双向迭代器,因此可以在任何标准序列迭代器上使用partition和stable_partition
6.stable_partition: partition的重载,用法类似stable_sort
7.堆算法:
• 函数:
○ make_heap:将某个区间转换成一个heap
○ push_heap(beg, end)/push_heap(beg, end, op>:将end元素之前的最后一个元素加入原本就是heap的[beg, end-1)区间内,使整个[beg, end)区间成为一个heap;
§ 调用者必须保证进入函数时,[beg, end-1)区间内的元素原本便已经形成一个heap,而新元素紧跟其后
§ 复杂度:对数,至少执行log(numElems次比较
○ pop_heap(beg, end)/pop_heap(beg, end, op):
§ 两种形式从heap[beg, end)内的最高元素移动到最后位置,并将剩余区间[beg, end-1)内的元素组织起来,成为一个新的heap
§ op(elem1, elem2):排序准则,可有可无
§ 调用者必须保证进入函数时[beg, end)区间内的元素原本已经形成一个heap
§ 复杂度:
○ sort_heap:对heap进行排序,完成后就不再是一个heap了
• 可以传递一个函数作为排序准则,默认的排序准则是operator<
• is_heap:检验区间内的元素是否排序成为一个堆
• is_heap_until:返回区间内第一个破坏heap排序状态的元素
五.已排序区间算法:以下算法适用前提是源区间必须在某个排序准则的作用下已经排好序
1.查找元素
• bool binary_search(beg, end, const T& value) / bool binary_search(beg, end, const T& value, op)
○ 调用者必须保证,进入算法之际,工作区间已经排序
○ op(elem1, elem2)
○ 两种形式都判断区间[beg, end)是否包含"和value等值"的元素
2.检查数个元素是否存在
• bool includes(beg, end, searchBeg, searchEnd)/bool includes(beg, end, searchBeg, searchEnd, op)
○ 两种形式都用来判断已排序区间[beg, end)是否包含另一个已排序区间[searchBeg, searchEnd)的全部元素
○ op(elem1, elem2)
○ 调用者必须确保,在进入算法之际两个区间都已经根据同一个准则排好序了
3.查找第一个或最后一个可能位置
• ForwardIterator lower_bound(beg, end, const T& value)/ForwardIterator lower_bound(beg, end, const T& value, op)
• ForwardIterator upper_bound(beg, end, const T& value)/ForwardIterator upper_bound(beg, end, const T& value, op)
○ 返回第一个大于等于value的元素位置,这是可插入元素值为value且不破坏区间[beg, end)已排序性的第一个位置
○ 返回第一个大于value的元素,这是可插入元素值为value且不破坏区间[beg, end)已排序性的最后一个位置
○ 如果不存在值为value的元素,都返回end
○ 若要同时获得lower_bound和upper_bound的结果,使用equal_range()
4.查找第一个和最后一个可能位置
• pair<ForwardIterator, ForwardIterator>equal_range(beg, end, const T& value)/pair<ForwardIterator, ForwardIterator>equal_range(beg, end, const T& value, op)
○ 两种形式都返回与value相等的元素所形成的区间pair(返回区间为[beg, end)),在此区间内插入值为value的元素并不会破坏[beg, end)区间的已排序性
○ 等效于:make_pair(lower_bound(…), upper_bound(…))
5.合并元素
两个已排序集合的总和
• OutputIterator merge(Beg, End, Beg2, End2, destBeg)/OutputIterator merge(Beg, End, Beg2, End2, destBeg, op)
○ 将两个源区间【beg,end)合并,使以destBeg起始之目标区间内含两个源区间的所有元素
○ 目标区间的元素都处于排序状态下
○ 返回目标区间内最后一个被复制元素的下一个位置
○ 源区间不会有任何变化
○ list和forward_list都提供一个特殊的成员函数merge来合并两个list
○ 如果要确保两个源区间中出现的元素在目标区间中只出现一次,使用set_union
○ 如果只想获得同时存在于两个源区间内的元素,使用set_intersection
• 两个已排序集合的并集:OutputIterator set_union(beg1,end1, beg2,end2,destBeg)/OutputIterator set_union(beg1,end1, beg2,end2,destBeg, op)
○ 两者都是将区间[beg1,end1)和[beg2, end2)内的元素合并,得到以destBeg起始的目标区间,后者内含的元素要么来自第一个区间,要么来自第二个区间,或者同时来自两者
○ 同时出现于两个源区间内的元素在并集区间中将只出现一次,但是如果原来的某个源区间内本身就存在重复的元素则目标区间也会存在重复元素
○ 返回最后一个被复制元素的下一位置
○ 目标区间内的元素都处于排序状态
○ 必须要保证目标区间有足够的空间,否则就要使用insert iterator
○ 源区间和目标区间两者不可重叠
• 两个已排序集合的交集:OutputIterator set_intersection(beg1, end1, beg2, end2, destbeg)/set_intersection(beg1, end1, beg2, end2, destbeg, op)
• 两个已排序集合的差集:
○ OutputIterator set_difference(beg1, end1, beg2, beg2, destbeg)/set_difference(beg1, end1, beg2, beg2, destbeg, op)
§ 目标区间的元素只存在于第一区间,不存在于第二区间
§ 返回最后一个被合并元素的下一个位置
○ OutputIterator set_symmetric_difference(beg1, end1, beg2, beg2, destbeg)/OutputIterator set_symmetric_difference(beg1, end1, beg2, beg2, destbeg, op)
§ 目标区间内含的元素或存在于第一源区间,或存在于第二源区间,不同时存在于两个区间内
• 合并连贯之已排序区间:void inplace_merge(beg1, beg2, end2)/inplace_merge(beg1, beg2, end2, op)
○ 将已排序源区间[beg1, beg2), [beg2, end2)合并,使区间[beg1, end2)成为两者之和
数值算法:#include
std::max(const T&a, const T& b):返回较大的数
void generate(ForwardIterator beg, ForwardIterator end, Func op): 调用op产生新值,并将它赋值给区间(beg, end)的所有元素
• 注意是每次给区间中的一个元素赋值时会调用一次op,所以调用的次数和区间中的元素个数相同
• 区间是(beg,end),即第二个和倒数第二个(目前测试是这样,见C++标准库10.1.2)
generator_n(OutputIterator beg, Size num, Func op):调用op产生新值,并将它赋值给以beg起始的区间内的前num个元素,如果num为负值不做任何事,返回最后被该动的元素的下一位置,注意是每次给区间中的一个元素赋值时会调用一次op,所以调用的次数和区间中的元素个数相同
accumulate(InputIterator beg, InputIterator end, T initValue)/accumulate(InputIterator beg, InputIterator end, T initValue, op):结合所有元素(求和,求乘积)
• 第一形式:计算initValue对区间[beg, end)内的每个元素的总和,具体:initValue=initValue+elem

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值