算法分类:
- 质变算法:在运算过程中会改变迭代器指向的值。质变算法一般提供两个版本,一是就地进行版本,如sort,另一个就是异地进行(copy)版本,如repalce()的另一个版本replace_copy()
- 非质变算法:如遍历、查找之类
STL的一般形式:
- 都需要一对迭代器,标识算法的操作区间,并提取迭代器的5个特性。
- 可能还需要一个函数对象,指明操作方法,如replace_if()就需要接收functor
- 最后一个元素称为end,而不用null,这样是因为能对其他容器带来泛型效果
所有的数值算法都实现与。常用算法定义于<stl_algobase.h>,其他stl算法都实现于SGI的<stl_algo.h>并被include了。
常见算法:
find类,以find()为例:
template <class _InputIter, class _Tp>
inline _InputIter find(_InputIter __first, _InputIter __last,
const _Tp& __val,
input_iterator_tag)
{
while (__first != __last && !(*__first == __val))
++__first;
return __first;
}
迭代器类型为InputIter,也就是所有容器的迭代器都可以直接使用这个算法,不同迭代器的++操作不同。
for_each
template <class _InputIter, class _Function>
_Function for_each(_InputIter __first, _InputIter __last, _Function __f) {
__STL_REQUIRES(_InputIter, _InputIterator);
for ( ; __first != __last; ++__first)
__f(*__first); // 调用仿函数,如果有返回值将被忽略
return __f;
}
严格意义来说,for_each不允许元素内容被修改,如果想一一修改元素,可以使用transform()。
search类
seach():
在一个区间[first1,last1) 中匹配第二个区间[first2,last2),方法很简单,就是模式匹配的暴力法。
lower_bound():
试图在[first,last) 中寻找元素value,如果没有找到,就返回一个迭代器,指向“如果这个元素,其应该出现的位置”。
算法有两个版本,一个是采用 operator < 比较,一个是采用仿函数 comp。
upper_bound():
也是在已排序的[first,last)中找value,返回value可被插入的最后一个位置,也就是说,不像lower_bound()指向value本身,而是指向最后一个value的后一个位置。
其也有两个版本,一个是采用 operator < 比较,一个是采用仿函数 comp。
binary_search():
就是利用lower_bound(),不过其返回值不是迭代器而是bool。也有两个版本。
Sort
SGI STL采用IntroSort(内省式排序),也就是InsertSort+QuickSort+HeapSort。
首先进行快排,快排递归深度可能很深,所以在第一个注意点是采用median-of-three方法,选取合适的枢轴,也就是从first、mid、end三个位置中,选择第二大的值做为枢轴。第二哥个注意点是递归深度不能太深,如递归深度到达10(这个值称为k,和元素的个数n有关 ,在2^k<n的约束条件下,k取最大值),就采用更稳定的堆排序(由于已经进行了10轮分割了,也不会造成很大的空间浪费)。
然后,当容器里的值到达一个接近排序完成的状态时(这个状态下,插入排序的速度很快),采用插入排序完成最终的排序。
其实直接用快排也可以吧,但为了性能优化,用IntroSort也是值得的。
注意:关系式容器(基于RB-tree)自带排序功能,不需要用sort,stack和queue不允许排序,用不到sort,list不属于RAI(随机访问迭代器),需要自己写一个sort函数。因此,只有vector和deque可直接用算法中的sort函数。