C++标准库提供了vector,map,set,list等等的容器,对于这些不同的容器,他们都应该有一些相通的算法,比如find,copy等等。那么我们是否每个算法要对每个容器都实行一遍实现呢?实际上虽然不同的容器的同一个算法的实现可能不同,但是他们的抽象思想确实一致的,因此我们可以用同一的格式来解决,这就是泛型算法。
泛型算法的基础
算法有很多,然而究其本质只有一条,那就是对数据的遍历。
对于不同的容器,他们的数据组织格式千差万别,那么我们的泛型算法在遍历的时候需要同一个的一种方式来对数据结构进行遍历,有什么方法能做到呢?当然就是迭代器了。不得不说迭代器是一个很伟大的发明,它屏蔽了不同数据结构内部的差异,用统一的方式对数据进行遍历。
常用的泛型算法
只读算法
find
find用于查找操作,返回值是迭代器。如下所示:1
2auto pos = find(ivec.begin(), ivec.end(), 5);
cout << *pos << endl;
accumulate
accumulate执行的是累加操作,可用于定义了operator+操作符的类型,如int,string等等
1 | #include "numeric" |
equal
equal用于比较两个序列是否保存相同的值,如下所示:
1 | bool ret = equal(ivec.begin(), ivec.end(), ivec1.begin()); |
equal要求第二个序列至少要跟第一个一样长。
for_each
for_each就是for循环。1
2
3
4void printWords(char c = ' ')
{
for_each(words.begin(), words.end(), [=, &os] (const string& s) {os << s << c});
}
写容器的算法
fill
用于给序列赋值1
fill(vec.begin(), vec.end(), 0);
fill_n
与fill一样,用于给序列赋值,但是fill_n的参数如下:1
fill(vec.begin(), n, 0);
它的第二个参数是数量,但是如果我们的容器是空的,如下所示,就有可能会导致未定义的行为1
2vector<int> vec;
fill_n(vec.begin(), 10, 0);
为了解决这个问题,可以使用back_inserter1
2vector<int> vec;
fill_n(back_inserter(vec), 10, 0);
copy
copy可以用于两个数组的copy操作1
2
3int a1[] = {0, 1, 2, 3};
int a2[sizeof(a1)/ sizeof(int)];
copy(begin(a1), end(a2), a2);
replace
replace用于在一个序列中,将val1的值替换为val2的值1
replace(vec.begin(), vec.end(), val1, val2);
排序
sort
sort是最重要的算法之一。sort的定义如下,它有三个参数,前两个微迭代器控制范围,最后一个是比较函数。这里如果不写,则用默认的比较函数
对于数值类型,默认重小到大排列,
对于字符串,默认为字典序排列。
而比较函数,可以是结构中定义operator<, lambda表达式,函数等方式解决。
1 | void sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) |
stable_sort
跟上面的sort一样的,是排序算法,只不过遇到相同的元素时,他会保证相同元素的最初始的位置不变动。所以我们称之为稳定的排序
unique
人如其名,unique算法保证返回的序列不存在重复元素,返回值为迭代器,为序列中不存在重复元素的下一个位置。
erase
删除,用于将序列中指定范围的元素删除
例子
假设我们有一个字符序列,我们需要将其按照字典序排列,并且删除重复的单词
1 | #include "vector" |