1、简介
标准库容器定义的操作非常少,标准库没有给容器添加大量的功能函数,而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是“泛型”的,可作用在不同类型的容器和不同类型的元素上。
标准容器定义了很少的操作:添加和删除元素,访问第一个和最后一个元素,获取容器的大小,并在某种情况下重设容器的大小,以及获取指向第一个元素和最后一个元素的下一位置的迭代器。
用户还希望对容器元素进行更多的其他有用的操作,如:给顺序容器中的元素排序或者查找某个特定的元素,或者查找最大或最小的元素等等。标准库并没有为每种容器类型都定义实现这些操作的成员函数(有的定义了),而是定义了一组“泛型算法”:因为他们实现共同的操作,所以称之为“算法”,而“泛型”指的是他们可以操作在多种容器类型上---不但可以在vector和list等标准库类型,也可用在内置数组类型上等。
大多数算法是通过遍历由两个迭代器标记的一段元素来实现功能。
2、常用泛型算法
(1)find算法(只读算法)
使用两个迭代器和一个值调用find函数,检查两个迭代器实参标记范围内的每一个元素,只要找到与给定的值相等,find就会返回指向该元素的迭代器,如果没有匹配的元素,find返回它的第二个迭代器实参,表示查找失败。于是,只要检查函数的返回值是否与它的第二个实参相等,就可得知元素是否找到了。
举个简单的例子:
int search_value = 42;
vector<int>::const_iterator result = find(vec.begin(),vec.end(),search_value);
if(result == vec.end())
cout<<"not present"<<endl;
else
cout<<"present"<<endl;
(2)accumulate算法(只读算法)
前两个形参指定要累加的元素范围,第三个形参是累加的初值,算法返回累加的结果,返回类型是第三个实参的类型。
举个简单的例子:
int sum = accumulate(vec.begin(),vec.end(),42);
string sum = accumulate(v.begin(),v.end(),string(""));
(3)fill算法(写算法)
将值写入到目标迭代器指定的范围内。前两个表示填充的范围
举个简单的例子:
fill(vec.begin(),vec.end(),0);
将vec容器中的所有元素重新赋值为0;
(4)fill_n算法(写算法)
fill_n(vec.begin(),10,0)
将vec容器开始处的10个元素赋值为0,假如容器为空或当前容器的元素个数少于10个,会出错。
back_inserter():插入迭代器。使用一个容器对象作为实参。back_inserter生成一个绑定在该容器上的插入迭代器,在试图通过这个迭代器给元素赋值时,赋值运算将调用push_back在容器中添加一个具有指定值的元素。如下:
vector<int> vec;
fill_n(back_insert(vec),10,0)
这样就不会出错,fill_n函数每写入一个值,都会通过back_inserter生成的插入迭代器实现。效果相当于在vec上调用push_back函数,在vec末尾添加10个元素,每个元素的值均为0。
(5)copy算法(写算法)
vector<int> ivec;
copy(ilst.begin(),ilst.end(),back_inserter(ivec));
将ilst中的所有元素复制给ivec容器中。其实这种效率不高,可在构造新容器的时候用ilst初始化,如:
vector<int> ivec(ilst.begin(),ilst.end());
(6)replace算法(写算法)
带有4个实参,前两个实参是替换时查找的范围,第3个实参是待替换的值,第4个实参是替换值,如:
replace(ilst.begin(),ilst.end(),0,42)
在ilst容器中寻找0,用42代替。
(7)replace_copy算法(写算法)
如果不想改变原来的序列,则调用replace_copy,这个算法接收第3个迭代器实参,指定保存调整后序列的目标位置。
如:
replace_copy(ilst.begin(),ilst.end(),back_inserter(ivec),0,42);
调用该函数后,ilst没有改变,ivec存储替换后的副本。
(8)sort排序算法
sort(words.begin(),words.end());
容器中的元素按字典顺序排列。
(9)unique算法:
适合于排序后的容器,删除相邻的重复元素。算法返回超出无重复的元素范围末端的下一位置。
如:
vector<string>::iterator end_unique = unique(words.begin(),words.end());
words.erase(end_unique,words.end());
(10)stable_sort算法
sort算法在给定的范围内,按照元素的从小到大排列元素。而stable_sort算法,增加了一个参数,称为谓词,用来控制根据什么原则排序。
如:bool IsShort(const string &s1, const string &s2)
{
return s1.size()<s2.size();
}
stable_sort(words.begin(),words.end(),IsShort);
则是根据元素(字符串)的长短来排序。
(11)count_if算法
记录满足某个条件的元素在容器中的数目,也需要谓词来说明规则。
如:bool GT6(const string &s)
{
return s.size()>=6;
}
vector<string>::size_type wc = count_if(words.begin(),words,end(),GT6);
小结:
容器和算法库是标准库的基础。标准库定义了超过100个算法,幸运的是,这些算法具有相同的结构,使他们更容易学习和使用。
算法和类型无关,他们通常在一个元素序列上操作,这些元素可以存储在标准容器类型,内置数组甚至是生成的序列上。
算法基于迭代器操作,从而实现类型无关性。
大多数算法使用一对指定元素范围的迭代器作为其头两个实参,其它的迭代器实参包括指定输出目标的输出迭代器,或者用于指定第二个输入序列的另一个或一对迭代器。
查找某个值的算法通常提供第二个版本,用于查找使谓词返回非零值的元素。对于这种算法,第二个版本的函数名字已_if后缀表示。类似的,很多算法提供所谓的复制版本,将(修改过的)元素写到输出序列上,而不是写回输入范围,这种版本的名字已_copy结束。