C++之泛型算法

这篇具有很好参考价值的文章主要介绍了C++之泛型算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

  • 大多数算法在头文件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文章来源地址https://www.toymoban.com/news/detail-435614.html

到了这里,关于C++之泛型算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • R语言【base】——data.frame():创建数据框,紧耦合的变量集合,它们共享矩阵和列表的许多属性,被大多数R建模软件用作基本数据结构。

    Package  base  version 4.2.0 创建数据框(data frame),紧耦合的变量集合,它们共享矩阵和列表的许多属性,被大多数R建模软件用作基本数据结构。 数据框:一种在统计分析和数据处理中常用的数据结构,由行和列组成,类似于电子表格。 参数【...】:这些参数的形式是 value 或

    2024年02月21日
    浏览(36)
  • C++之泛型算法

    大多数算法在头文件algorithm中,在头文件numeric中定义了一组数值泛型算法。理解算法最基本的方法就是了解他们是否读取元素,改变元素,或是重排元素顺序 使用STL算法经常需要使用函数对象和函数适配器,所以需要#include 所有算法都被设计用来处理一个或多个iterator区间,

    2024年02月03日
    浏览(26)
  • 选择排序算法之泛型优化

    工作原理: 每一次从待排序的数据元素中选中最小的一个元素,然后,再从剩余未排序元素中继续寻找最小元素,将2个元素交换位置,就达到了已排序的元素一直是从小到大了。 这个算法的时间复杂度为O(n²),空间复杂度为O(1)。 当然,为了匹配多种类型的对象,可以使用

    2024年02月06日
    浏览(33)
  • Go 泛型之泛型约束

    目录 Go 泛型之泛型约束 一、引入 二、最宽松的约束:any 三、支持比较操作的内置约束:comparable 四、自定义约束 五、类型集合(type set) 六、简化版的约束形式 七、约束的类型推断 八、小结 虽然泛型是开发人员表达“通用代码”的一种重要方式,但这并不意味着所有泛型

    2024年02月04日
    浏览(28)
  • java入坑之泛型

    Java泛型是JDK 5中引入的一个新特性,它提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这意味着你可以使用一套代码来处理多种不同类型的数据 ArrayListE,E表示元素El

    2024年02月10日
    浏览(31)
  • Java之泛型

    泛型: 泛型实现了参数化类型的概念,使代码可以应用于多种类型。 泛型的目的是希望类或方法能够具有最广泛的表达能力。 Java的泛型的主要目的之一就是用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。 泛型类: 类型参数:用尖括号括住,实际

    2024年02月11日
    浏览(30)
  • TypeScript 进阶之泛型

    避免代码重复和创建可重用类型是编写干净代码的重要部分。 将所有类型属性都设置为可选 Required 与 Partial 相反。它构造一个类型,其中需要该类型的所有属性。它可用于确保没有可选属性出现在类型中。 多属性的对象中摘取某些属性。 键可以是字符串文字或字符串文字的

    2024年01月23日
    浏览(29)
  • 30天拿下Rust之泛型

    概述         在Rust语言中,泛型是一种强大的工具,它允许我们编写可复用且灵活的代码。通过泛型,我们可以创建适用于多种类型的数据结构和函数,而无需为每种类型都重复编写相同的逻辑。在Rust中,泛型通过指定类型参数来实现,这些类型参数会在编译时被具体类

    2024年03月17日
    浏览(40)
  • Rust之泛型、trait与生命周期

    泛型是具体类型或其他属性的抽象替代。在编写代码时,可以直接描述泛型的行为,或者它与其他泛型产生的联系,而无须知晓它在编译和运行代码时采用的具体类型。 们可以在声明函数签名或结构体等元素时使用泛型,并在随后搭配不同的具体类型来使用这些元素。 当使

    2024年02月13日
    浏览(26)
  • C#(六十二)之泛型的约束

    类型约束 基类约束有两个重要的目的。 1:它允许在泛型类中使用有约束指定的基类成员。 2:确保只能使用支持指定基类或派生类的类型实例。 约束是使用 where 上下文指定的。 下表列出了五种类型的约束: 约束 说明 T:struct 类型参数必须是值类型。可以指定除

    2024年02月17日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包