10-2 初识泛型算法

  • 泛型算法和容器一样,具有一致的结构
  • 一般都接受一个”迭代器范围“
  • 理解算法最基本的方法就是了解他们是否
    • 读取元素
    • 改变元素
    • 重排元素

10.2.1 只读算法

常见的几个只读算法

  1. find
  2. count
  3. accumulate
  4. equal

accumulate前两个参数接受一个迭代器范围,最后一个参数接受初值

//对vector中的所有元素求和,和的初始值为0
int sum = accumulate(vec.cbegin(), vec.cend(), 0);
  • 因为是“只读”,不会改变元素,所以采用常量引用
  • 第三个参数的类型决定了函数使用哪种“+”以及返回值的类型

算法和元素的类型#

accumulate使用第三个参数作为求和的起点,隐含了两个编程假定

  1. 第三个参数定义了“+”操作
  2. 迭代器范围内的元素类型与第三个参数的类型匹配或者可以转换为第三个参数
//v的类型是vector<string>
string sum = accumulate(v.cbegin(), v.cend(), ""); //错误,“”类型为const char *,没有定义加法操作

string sum = accumulate(v.cbegin(), v.cend(), string(" "));

操作两个序列的算法#

另一个只读算法是equal,用于确定两个序列是否保存相同的值。

它将第一个序列中的每个元素与第二个序列中的对应元素进行比较。如果所有对应元素都相等,则返回true,否则返回false。

此算法接受三个迭代器:前两个(与以往一样)表示第一个序列中的元素范围,第三个表示第二个序列的首元素:

//roster2中的元素数目应该至少与roster1中的一样多
equal(rester1.cbegin(), roster1.cend(), roster2.cbegin());

重要的编程假设

  1. 两序列中的元素不必相同,只要能用“==”比较即可
  2. 那些只接受一个单一迭代器来表示第二个序列的算法,都假定第二个序列至少与第一个序列一样长。

10.2.2 写容器元素的算法

写操作写入的元素的数目<=容器的大小;毕竟泛型算法无法改变容器的大小

fill(vec.begin(), vec.end(), 0);//所有元素重置为0
//将一个子序列设置为10
fill(vec.begin(), vec.begin()+vec.size()/2, 10);

算法不检查写操作#

vector<int> v;  //空容器
fill_n(v.begin(), v.size(), 0); //正确:所有元素重置为0    
fill_n(v.begin(), 10, 0); //错误:v是空容器

第二个操作的结果是未定义的

不要对空容器使用写定义

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

介绍back_inserter#

一种保证算法有足够元素空间来容纳输出数据的方法是使用插入迭代器( insertiterator)

插入迭代器是一种向容器中添加元素的迭代器。

通常情况,当我们通过一个迭代器向容器元素赋值时,值被赋予迭代器指向的元素。而当我们通过一个插入迭代器赋值时,一个与赋值号右侧值相等的元素被添加到容器中。

back_inserter()函数

  • 接受一个容器引用
  • 返回一个与该容器绑定的迭代器
  • 使用迭代器赋值时,赋值运算符会调用push_back把给定值插入容器中

back_inserter()定义在头文件iterator中

vector<int> vec;  //空向量
auto it = back_inserter(vec);//通过it赋值会添加元素
*it = 42;//现在vec中有一个元素42
vector<int> vec;
fill_n(vec.begin(), 10, 0);//错误的:算法不能改变容器大小
fill_n(back_inserter(vec), 10, 0);//正确的:插入迭代器会插入元素

拷贝算法#

copy()

  • 接受三个参数,前两个表示迭代器范围,第三个表示拷贝的目的序列

  • 目的序列元素个数 >= 输入序列

    image-20220223143318117

  • 返回拷贝序列的尾后迭代器:上例中返回指向a2最后一个元素的后一个位置的迭代器

算法的拷贝版本#

algorithmName_copy()

//把ilst中的0替换为42
replace(ilst.begin(), ilst.end(), 0, 42);
replace(ilst.cbegin(), ilst.cend(), back_inserter(ivec), 0, 42);
//把ilst中的0替换为42,但ilst不会改变,而是把替换后的结果拷贝到ivec中

10.2.3 重排容器的算法

消除重复单词#

sort(迭代器范围,比较函数):对容器进行排序

unique(迭代器范围):将不重复元素放在开始部分,返回不重复区域的后一个位置的迭代器

void elimDups(vector<string> &words){
    //按字典排序words,以便查找重复单词
    sort(words.begin(), words.end());
    //unique重排输入范围,使得每个单词只出现一次
    //排列在范围前部,返回指向不重复区域之后一个位置的迭代器
    auto end_unique = unique(words.begin(), words.end());
    //使用earase删除重复单词
    words.erase(end_unique, words.end());
}

sort后:

image-20220223145143472

unique后:

image-20220223145155984

posted @   咪啪魔女  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示