C++_泛型算法知识点总结

泛型算法

大多数算法都定义在头文件algorithm中。标准库还在头文件numeric中定义了一组数值泛型算法。

1.   只读算法

1.1.查找对象的算法

[1]. find(beg,end, val) 在迭代器beg和end范围内查找val,返回一个迭代器,如果查找成功,返回指向输入序列中第一个等于val的元素;否则返回end。

[2].find_if(beg,end, predicate)  find_if接受一对迭代器和一个谓词,find_if算法对输入序列中的每个元素调用给定的这个谓词。它返回第一个使谓词返回非0值的元素的迭代器,如果不存在这样的元素,则返回尾迭代器。

[3].count(beg,end, val)在迭代器beg和end范围内查找val,返回匹配成功的数目。

[4].count_if(beg,end, predicate)  count_if接受一对迭代器和一个谓词,会对输入范围内的每个元素执行。count_if返回一个计数值,表示谓词有多少次为真。

1.2.求和算法

  accumulate(beg, end, initialVal),定义在头文件numeric中。accumulate的第三个参数决定了函数中使用哪个加法运算符以及返回值的类型。该算法可用于元素定义了加法运算符的类型,如string。

1.3.序列比较算法

  equal(beg1, end1, beg2),用于确定两个序列是否保存相同的值。它将第一个序列中的每个元素与第二个序列中的对应元素进行比较。如果所有元素都相等,则返回true,否则返回false。此算法接收3个参数:前两个表示第一个序列中的元素范围,第三个表示第二个序列的首元素。

HINT:那些接收一个单一迭代器来表示第二个序列的算法,都假定第二个序列与第一个序列一样长。

2.   写容器算法

[1].fill(beg, end, val)   算法fill接受一对迭代器表示一个范围,还接受一个值作为第三个参数。fill将给定的这个值赋予输入序列中的每个元素。

[2].fill_n(beg, n, val)  函数fill_n接受一个单迭代器、一个计数值和一个值。它将给定值赋予迭代器指向的元素开始的指定个元素。如:

fill_n(vec.begin(),vec.size(), 0);

[3].back_inserter(container)  back_inserter接收一个指向容器的引用,返回一个与该容器绑定的迭代器。当我们通过此迭代器赋值时,赋值运算符会调用push_back将一个具有给定值的元素添加到容器中。例如:

vector<int> vec;

auto it = back_inserter(vec);

fill_n(it, 10, 0);

[4].copy(beg1, end1, beg2) 拷贝算法是另一个向目的位置迭代器指向的输出序列中的元素写入数据的算法。此算法接受三个迭代器,前两个表示一个输入范围,第三个表示目的序列的起始位置。copy返回的是其目的位置迭代器(递增后)的值。

WARNINGS:向目标位置迭代器写入数据的算法假定目的位置足够大,能容纳写入的元素。

[5].replace(beg, end,initval, reval)  replace算法读入一个序列,并将其中所有等于给定值的元素都改为另一个值。此算法接受4个参数:前两个是迭代器,表示输入序列,后两个一个是要搜索的值,另一个是新值。

[6].transform(beg1, end1,beg2, predicate)  transform算法将输入序列通过谓词操作输出到beg2的序列中。

例如:我们可以使用transform算法和一个lambda来将一个序列中的每个负数替换为其绝对值。

transform(vi.begin(), vi.end(), vi.begin(), [](int i){returnI < 0 ? -I : I;});需要有返回值。

3.重排容器元素的算法

[1].sort(beg, end,(predicate))  sort算法接受两个迭代器,表示要排序的元素范围。

[2].stable_sort(beg, end, (predicate))  stable_sort算法对容器进行排序,维持相等元素的原有顺序。

[3].unique(beg, end)  unique算法重排输入序列,将相邻的重复项“消除”,并返回一个指向不重复值范围末尾的迭代器。

[4].partition(beg, end, predicate)  partition算法接受一个输入序列和一个谓词,对容器进行划分,使得谓词为true的值会排在容器的前半部分,而使谓词为false的值会排在后半部分。

[5].reverse(beg, end) reverse算法接受输入序列,并将其中元素反转。

 

4.定制操作

对于一个对象或一个表达式,如果可以对其使用调用运算符,则称它为可调用的。即,如果e是可调用的表达式,则我们可以编写代码e(args),其中args是一个逗号分隔的一个或多个参数的列表。

一个lambda表达式表示一个可调用的代码单元,我们可以将其理解为一个未命名的内联函数。一个lambda表达式具有如下形式:

[capture list] (parameterlist) ->return type { function type}

1.   在lambda中忽略括号和参数列表等价于指定一个空参数列

2.   如果忽略返回类型,lambda根据函数体中的代码推断出返回类型。如果函数体只有一个return语句,则返回类型从返回的表达式的类型推断出来,否则,返回类型为void。

3.   一个lambda只有在其捕获列表中捕获一个它所在函数中的局部变量,才能在函数体中使用该变量。

5.参数绑定

      标准库函数bind定义在头文件functional中,可以将bind函数看做一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表。

调用bind的一般形式为: auto newCallable = bind(callable, arg_list)

使用bind,我们可以将原来基于lambda的find_if调用:

auto wc = find_if(words.begin(),words.end(), [sz](const string& a));

替换为如下使用check_size的版本:

auto wc =find_if(words.begin(), words.end(),

bind(check_size, _1, sz));

TIPS:

1.   引用捕获:如果我们捕获一个指针或迭代器,或采用引用捕获方式,就必须确保在lambda执行时,绑定到迭代器、指针或引用的对象仍然存在。而且,需要保证对象具有预期的值。

2.   对于那种只在一两个地方使用的简单操作,lambda表达式是最有用的,如果我们需要在很多地方使用相同的操作,通常应该定义一个函数,而不是多次编写相同的lambda表达式。

BEST PRACTICES:对于只读取而不改变元素的算法,通常最好使用cbegin()和cend()。但是,如果你计划使用算法返回的迭代器来改变元素的值,就需要使用begin()和end()的结果作为参数。

6.特定容器算法

      与其他容器不同,链表类型list和forward_list定义了几个成员函数形式的算法。特别是,它们定义了独有的sort,merge,remove,reverse和unique。这些链表版本的算法的性能比对应通用版本好得多。

Best Practices: 对于list和forward_list,应该优先使用成员函数版本的算法而不是通用算法。

list和forward_list成员函数版本的算法

这些操作都返回void

lst.merge(lst2)

 

lst.merge(lst2, cmp)

将来自lst2的元素合并入lst。lst和lst2都必须是有序的。元素将从lst2中删去,在合并之后lst2变为空。第一个版本使用<运算符·;第二个版本使用给定的比较操作。

lst.remove(val)

lst.remove_if(pred)

调用erase删除掉与给定值相等或令一元谓词为真的每个元素。

lst.reverse()

反转lst中的元素

lst.sort()

lst.sort(cmp)

使用<或给定比较操作排序元素

lst.unique()

lst.unique(pred)

调用erase删除同一个值的连续拷贝。第一个版本使用==;第二个版本使用谓词

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值