STL中算法是基于迭代器来实现的。
有了容器中迭代器的实现(对operator*、operator++等的重载),STL中大部分算法实现就显得很简单了。
先看一例关于find算法的实现:
1 template <class InputIterator, class T> 2 InputIterator find(InputIterator first, InputIterator last, const T& value) { 3 // 直接利用iterator中的operator++、operator*、operator!=实现 4 // 默认使用class T的operator!= 5 while (first != last && *first != value) ++first; 6 return first; 7 } 8 9 template <class InputIterator, class Predicate> 10 InputIterator find_if(InputIterator first, InputIterator last, 11 Predicate pred) { 12 // 能接受一个仿函数 用来指定find的条件 13 while (first != last && !pred(*first)) ++first; 14 return first; 15 }
其它的基本算法实现都差不多,它们一般只是执行单纯的数据移动、线性查找、计数、循环遍历等操作。
比较复杂的算法一般都关于排列、排序之类的,这次只要说说SGI STL中sort()的实现。
SGI STL中的sort()
SGI STL中的排序算法混合了quick sort、heap sort、insert sort三种排序算法。
总体上用的是quick sort,分割到一定深度(2^k < = n)的时候会使用heap sort,
在分割区域元素大小小于阀值(16)时最后执行的是insert sort。
下面是sort()的的基本框架:
1 template <class RandomAccessIterator> 2 inline void sort(RandomAccessIterator first, RandomAccessIterator last) { 3 if (first != last) { 4 // 使用quick sort、heap sort排序 直到所有分割区域元素大小都小于阀值 __stl_threshold = 16 5 __introsort_loop(first, last, value_type(first), __lg(last - first) * 2); 6 // 最后对其分割区域都执行一次insert sort 7 __final_insertion_sort(first, last); 8 } 9 } 10 11 // 阀值k满足2^k <= n 12 template <class Size> 13 inline Size __lg(Size n) { 14 Size k; 15 for (k = 0; n > 1; n >>= 1) ++k; 16 return k; 17 }
然后看看introsort_loop的实现:
1 template <class RandomAccessIterator, class T, class Size> 2 void __introsort_loop(RandomAccessIterator first, 3 RandomAccessIterator last, T*, 4 Size depth_limit) { 5 while (last - first > __stl_threshold) { // 元素足够少 返回由insert sort处理 6 if (depth_limit == 0) { // 分割恶化 采用heap_sort 7 partial_sort(first, last, last); // 实现为heap_sort 8 return; 9 } 10 // 深度 11 --depth_limit; 12 // key为first middle last的中值 13 RandomAccessIterator cut = __unguarded_partition 14 (first, last, T(__median(*first, *(first + (last - first)/2), 15 *(last - 1)))); 16 // 递归的处理[cut, last) 17 __introsort_loop(cut, last, value_type(first), depth_limit); 18 // 返回while 继续处理[first, cut) 19 last = cut; 20 } 21 }