C++ Primer第十章①

C++ Primer

泛型算法

我们前一章学习了容器,不知道你有没有发现,其实容器是一个模板类,就是说在类的上面还有一层,看下面这句话:

vector<int> a;

这里面包含了模板类vector->类vector<int>->对象a,也就是说vector不独立于任何数据类型,它是在数据类型之上的那一层,模板类。

这个特征跟我们这一章要学的泛型算法有些类似,我们有很多的标准库容器,那我们是不是要给每个标准库容器写算法呢?C++不是这样做的,这样太麻烦了,C++的做法是提供一组算法,独立于任何特定的容器,这些算法是类型无关的,是泛型(generic)的:就是说它们可以用于不同类型的容器和不同类型的元素。

在前面学的顺序容器中,我们提供的操作都很基本,增删元素,访问头尾元素等,这一章我们会提供更多有用的操作(而且它们基本可以用于所有的容器)

概述

大多数算法都定义在algorithm中。

算法一般不直接操作容器,而是遍历由两个迭代器指定的一个元素范围(这个就是有点泛型的意思了)。我们来举个例子,假定有一个int的vector,我们要判断里面是否包含一个特定值,代码如下:

int val = 24;
auto res = find(vec.begin(), vec.end(), val);
cout << (res == vec.end() ? "不存在" : "存在") << endl;

是不是超级简单?而且这个find函数可以适用于各种容器,是泛型的。

为什么会这么6这么神奇呢,我们来仔细看看find算法是怎么做的: find算法通过迭代器去依次访问元素,找到就停止,直到尾后元素。

这些都不依赖于容器所保存的元素类型或者是容器类型,它就是迭代器去访问。

迭代器令算法不依赖于容器,这个我们知道了,还有一句话是这样的,但算法依赖于元素类型的操作,这句话怎么理解呢?因为算法在执行时肯定要操作元素,比如我们的find算法,它至少要使用==符号来判等,所以就要求元素类型支持 ==,这里的类型是int,当然支持了。

算法本身不会执行容器的操作,它们只会运行于迭代器之上

初识泛型算法

我们学习的泛型算法基本都对一个范围内的元素进行操作,这个范围由两个参数表示,前一个指向要处理的第一个元素,后一个指向尾元素之后的位置。

只读算法

只读取其输入范围内的元素,从不改变元素。例如之前的find函数,再来一个例子:

int sum = accumulate(vec.cbegin(), vec.cend(), 0);

这个函数是对容器内元素求和,第三个参数是求和的初值,这个算法要求容器内的元素类型支持+,再来一个例子,string定义了+,所以可以对string求和:

int sum = accumulate(vec.cbegin(), vec.cend(), string("")); //泛型,跟上面几乎一样
操作两个序列的算法
equal(vec1.cbegin(), vec1.cend(), vec2.cbegin());

vec2元素数量要大于等于vec1,前面每个元素都对应相等蔡返回true

写容器元素的算法

举个例子:

fill(vec.begin(), vec.end(), 0); //将所有元素重置为0
//但是算法不会去检查写这个操作,例如
vector<int> v;
fill_n(v.beg(), 10, 0); //这个函数企图把v开头的10个元素置为0
//但是会出错,而且不会报编译错误

//再介绍一个函数back_inserter,定义在iterator头文件
vector<int> vv;
auto it = back_inserter(vec); //返回一个插入迭代器,通过向插入迭代器赋值
*it = 24; //就可以成功插入了,vv中有一个元素24
//这里我们调用了它,作用是用插入迭代器来插值
fill_n(back_insertet(v), 10, 0);

拷贝算法

甩代码:

int a1[] = {0, 1, 2, 3, 4};
int a2[sizeof(a1)/sizeof(*a1)]; //相同元素个数
auto ret = copy(begin(a1), end(a1), a2); //把a1的内容拷贝给a2,返回a2尾元素之后的值

还有一个replace算法:

replace(list.begin(), list.end(), 0, 42); //把list中所有的0改为42
//还有一种重载,保留了原来的list
replace(list.cbegin(), list.cend(), back_inserter(ivec), 0, 42);
//list不变,ivec包含list的一份拷贝,不过里面的0都变成42了

重排容器元素的算法

我们要通过一个任务来学习这部分,假定我们要化简一个vector,使得里面保存的单词只出现一次:

//假设原来的vector为a, b, d, c, a, b
void Unique(vector<string> &words)
{
    sort(word.begin(), words.end()); //a, a, b, b, c, d
    auto end_unique = unique(words.begin(), words.end()); //a, b, c, d, a, b
    //end_unique的位置就是第一个重复的元素位置
    words.eraser(end_unique, wors.end()); //a, b, c, d
}
#C++工程师#
全部评论
int sum = accumulate(vec.cbegin(), vec.cend(), string("")); //泛型,跟上面几乎一样 文章中部,不是 int sum 而是 string sum 虽然有点小错误,但是无所谓,谢谢楼主的好文!
点赞 回复 分享
发布于 2017-09-21 11:29

相关推荐

点赞 评论 收藏
分享
05-11 11:48
河南大学 Java
程序员牛肉:我是26届的双非。目前有两段实习经历,大三上去的美团,现在来字节了,做的是国际电商的营销业务。希望我的经历对你有用。 1.好好做你的CSDN,最好是直接转微信公众号。因为这本质上是一个很好的展示自己技术热情的证据。我当时也是烂大街项目(网盘+鱼皮的一个项目)+零实习去面试美团,但是当时我的CSDN阅读量超百万,微信公众号阅读量40万。面试的时候面试官就告诉我说觉得我对技术挺有激情的。可以看看我主页的美团面试面经。 因此花点时间好好做这个知识分享,最好是单拉出来搞一个板块。各大公司都极其看中知识落地的能力。 可以看看我的简历对于博客的描述。这个帖子里面有:https://www.nowcoder.com/discuss/745348200596324352?sourceSSR=users 2.实习经历有一些东西删除了,目前看来你的产出其实很少。有些内容其实很扯淡,最好不要保留。有一些点你可能觉得很牛逼,但是面试官眼里是减分的。 你还能负责数据库表的设计?这个公司得垃圾成啥样子,才能让一个实习生介入数据库表的设计,不要写这种东西。 一个公司的财务审批系统应该是很稳定的吧?为什么你去了才有RBAC权限设计?那这个公司之前是怎么处理权限分离的?这些东西看着都有点扯淡了。 还有就是使用Redis实现轻量级的消息队列?那为什么这一块不使用专业的MQ呢?为什么要使用redis,这些一定要清楚, 就目前看来,其实你的这个实习技术还不错。不要太焦虑。就是有一些内容有点虚了。可以考虑从PR中再投一点产出
投递美团等公司9个岗位
点赞 评论 收藏
分享
评论
6
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务