先强调一下,这里的泛型算法实际不光光是对vector的操作,对于“顺序容器”均可以。
但是什么是顺序容器:
我们都知道,容器就是一些特定类型对象的集合。而顺序容器为程序员提供了控制元素存储和访问的能力。这种容器的一个显著的特征,就是容器中元素的顺序不依赖于元素的值,而是与加入容器时的位置有关。常见的顺序容器有vector、deque(双端队列)、list(双向链表)、forward_list(单向链表)、array(固定大小数组)、string。
了解了顺序容器,现在以vector为例,做下文的说明。
顺序容器本身只定义了很少的操作,这些操作我在前面的博客(点这里)也有写过。比如添加、删除元素,访问元素、获得迭代器等。但是现实中,我们用户肯定希望有更多的操作供自己使用,比如查找、替换、删除特定元素,重新排列元素等。为了实现上面的功能,程序员可能需要写一大段代码来将其实现。
为了解决这个问题,增加对于vector的操作种类,标准库给出了一组“泛型算法(generic algorithm)”。称其“算法”,是因为他们实现了一些经典算法的公共接口,比如排序、搜索。称其为“泛型”,是因为他们可以用于不同类型的元素和多种容器类型。
下面讲一下具体有哪些泛型算法。
大多数的算法都定义在头文件algorithm中,标准库还在头文件numeric中定义了一组数值泛型算法。一般情况下这些算法并不直接操作容器,而是遍历由两个迭代器指定的一个元素范围。
这些算法大致可以分为下面几类:
顾名思义,这种算法只读取其输入范围内的元素,并不改变元素。
<1>find(vec.begin() , vec.end(), val)
在vec中搜索val,返回第一个等于val的元素的迭代器。如果范围内无匹配元素,则放回vec.end()。
<2>count(vec.begin() , vec.end(), val)
在vec中搜索val,返回val在vec中出现的次数。
<3>accumulate(vec.begin() , vec.end(), val)
在vec中的元素求和,和的初始值设为val。val的类型决定了函数使用哪个加法运算符以及返回值类型。
<4>equal(vec1.begin() , vec1.end(), vec2.begin())
比较两个vector是否相等,返回值为bool型。
<1>fill(vec.begin(), vec.end(), val)
将vec中的元素重置为val
<2>fill_n(dest , n , val)
将从dest开始的n个元素重置为val。这里的dest是一个指向某个元素的迭代器。注意:这里的vec不能是空的,如果是空,那么上面的操作将会出现未知结果。
<3>back_inserter(vec)
向容器中添加元素的迭代器,故称之为插入迭代器。通常来说,当我们通过迭代器来给容器赋值时,值被赋予迭代器指向的元素。而当我们通过一个插入迭代器赋值时,一个与赋值号右侧值相等的元素被添加到容器中。back_inserter接收一个指向容器的引用,返回一个与该容器绑定的插入迭代器。当我们通过此迭代器赋值时,赋值运算符会调用push_back将一个具有给定值的元素添加到容器中。比如:
vector
auto it = back_inserter(vec); //通过它赋值会将元素添加到vec中
*it = 42; //vec中现在有一个元素,值为42
我们常常使用back_inserter来创建迭代器,作为泛型算法的目的位置使用。比如:
vector
fill_n(back_inserter(vec), 10 ,0); //添加10个元素到vec。
可以发现,前面说fill_n的vec不能为空,否则将会出现未知结果,而这里back_inserter相当于给vec push_back 了10个位置,然后填充,故这里的用法是可以的。
<4>copy(vec1.begin(), vec1.end(), vec2.begin())
将vec1中的内容拷贝到vec2中,故这里要求vec2的长度必须要大于等于vec1的长度。
<5>replace(vec.begin(), vec.end(), val1 ,val2)
将vec中的所有val1都替换为val2。
<6>replace_copy(vec1.begin(), vec1.end(),vec2.begin(), val1 ,val2)
替换后vec1中的值并未改变,而是将vec1拷贝到vec2中,并将vec2中的所有val1都替换为val2。
sort(vec.begin() , vec.end());
对vec中的内容按字典顺序排序
unique(vec.begin(), vec.end());
将vec中重复的数据删除,返回指向不重复区域之后一个位置的迭代器。值得注意的是这个删除操作只是将vec中的数据清空,但是vec的大小不变。即假设原vec中有40个元素,其中重复的有5个,那么经过unique操作后,这些重复元素重复的部分就不见了,vec中非空数据变成了35个,剩下的5个空间里面的数据为空。但是vec的size仍旧为40。要想真正的删除这些元素,还需用到容器本身的操作,erase。