STL源码剖析:算法
Posted chusiyong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL源码剖析:算法相关的知识,希望对你有一定的参考价值。
启
-
-
算法好坏的衡量标准:时间和空间,单位是对数、一次、二次、三次等
-
算法中处理的数据,输入方式都是左闭又开,类型就迭代器, 如:[first, last)
-
STL中提供了很多算法,我们只研究感兴趣的几种
copy函数
-
拷贝[first, last)到[result, reslut+(last - first))
-
总体考虑:对象能够直接在内存级别拷贝,还是需要单独拷贝
-
设计技巧:重载和特化
-
如下图所示:
template<class InputIterator, class OutputIterator> inline OutputIterator copy(InputIterator first, InputIterator last, OutputIterator reslut) return __copy_dispatch<InputIterator, OutputIterator>()(first, last, result); // 特化 inline char* copy(const char* first, const char* last, char* result) memmove(result, first, last - first); return result + (last - first); // 特化 inline wchar_t* copy(const wchar_t* first, const wchar_t* last, wchar_t* result) memmove(result, first, sizeof(wchar_t) * (last - first)); return result + (last - first);
template<class InputIterator, class OutputIterator> struct __copy_dispatch OutputIterator operator()(InputIterator first, InputIterator last, OutputIterator reslut) return __copy(first, last, result, iterator_category(first)); // 特化 template <class T> struct __copy_dispatch<T*, T*> T* operator()(T* first, T* last, T* result) typedef typename __type_traits<T>::has_trival_assignment_operator t; return __copy_t(first, last, result, t()); // 特化 template <class T> struct __copy_dispatch<const T*, T*> T* operator()(const T* first, const T* last, T* result) typedef typename __type_traits<T>::has_trival_assignment_operator t; return __copy_t(first, last, result, t());
template<class InputIterator, class OutputIterator> inline OutputIterator __copy(InputIterator first, InputIterator last, OutputIterator reslut, input_iterator_tag) // 以判断迭代器是否相同为标准,速度慢 for(; first != last; ++result, ++first) *result = *first; return result; template<class InputIterator, class OutputIterator> inline OutputIterator __copy(InputIterator first, InputIterator last, OutputIterator reslut, random_access_iterator_tag) // 完全是为了复用 return __copy_d(first, last, result, distance_type(first)); template<class InputIterator, class OutputIterator, class Distance> inline OutputIterator __copy_d(InputIterator first, InputIterator last, OutputIterator reslut, Distance*) // 以判断n值是否大于0为标准,速度快 for(Distance n = last - first; n > 0; --n, ++result, ++first) *result = *first; return result;
templat <class T> inline T* __copy_t(const T* first, const T* last, T* result, __true_type) // 直接复制内存 memmove(result, first, sizeof(T) * (last - first)); return result + (last - first); templat <class T> inline T* __copy_t(const T* first, const T* last, T* result, __true_type) // 每个数据单独复制 return __copy_d(first, last, result, (ptrdiff_t*)0);
copy_back函数
-
copy_back和copy的设计方式基本相同,问题的区别是拷贝的方向不同,copy是从first开始到last拷贝,copy_back是从last开始到first拷贝
-
copy_back的拷贝过程:
*(result - 1) = *(last - 1), *(result - 2) = *(last - 2)...
find函数
-
在[first, last)中找出第一个匹配的数据,返回指向该数据的Iterator
template <class InputIterator, class T> InputIterator find(InputIterator first, InputIterator last, const T& value) while(first != last && *first != *last) ++first; return first;
sort函数
-
插入排序
-
优点:对于小型,基本有序的数据进行排序,效率最高
-
缺点:对于大型数据,完全无序,效率非常低
-
-
堆排序
-
优点:对大型数据表现良好,所需的额外存储空间是和数据等同的大小
-
缺点:对于小型数据不合适
-
复杂度:平均O(NlogN),最坏O(N^2)
-
-
快速排序
-
优点:对于大型数据表现良好
-
缺点:递归调用耗资源,不适用于小型数据
-
复杂度:平均O(NlogN),最坏O(NlogN)
-
-
STL中的排序算法
-
如果数据个数大于16,使用快速排序,如果快速排序递归的层次超过一定阈值,使用堆排序
-
如果数据小于16,直接使用插入排序
-
原因:
-
小数据直接使用插入排序,效率高
-
大型数据一开始就使用堆排序,复杂度是O(NlogN),一开始使用快速排序效率低于O(NlogN),如果一直使用快速排序,算法的复杂度会降低到最坏O(N^2),所以先快速排序再堆排序
-
-
-
插入排序算法源码
template <class RandomAccessIterator> void __insert_sort(RandomAccessIterator first, RandomAccessIterator last) if(first == last) return; for(RandomAccessIterator i = first + 1; i != last,; i++) __linear_insert(first, i, value_type(first)); template <class RandomAccessIterator, class T> inline void __linear_insert(RandomAccessIterator first, RandomAccessIterator last, T*) T value = *last; if(value < first) // 需要插入的值比头部的值还小,直接整体拷贝 copy_back(first, last, last+1); *first = value; else // 从后向前,依次比较拷贝 __unguarded_linear_insert(last, value); template <class RandomAccessIterator, class T> void __unguarded_linear_insert(RandomAccessIterator last, T value) --next; while(value < *next) *last = *next; last = next; --next; *last = value;
- 快速排序算法源码
// 取三值中点 template <class T> inline const T& _median(const T& a, const T& b, const T& c) if(a < b) if(b < c) return b; else if(a < c) return c; else return a; else if(a < c) return a; else if(b < c) return c; else return b;
template <class RandomAccessIterator, class T> RandomAccessIterator __unguarded_partition(RandomAccessIterator first, RandomAccessIterator last, T pivot) while(true) while(*first < pivot) ++first; --last; while(pivot < *last) --last; if(!(first < last)) return first; iter_swap(first, last); ++first;
-
堆排序算法源码
-
见序列式容器中的堆章节
-
-
STL中的排序算法源码
template <class RandomAccessIterator> inline void sort(RandomAccessIterator first, RandomAccessIterator last) if(first != last) // 快速排序和堆排序 __introsort_loop(first, last, value_type(first), __lg(last - first) * 2); // 插入排序 __final_insertion_sort(first, last) // 找出2^k < n的最大k值 templat <class Size> inline Size __lg(Size n) Size k; for(k = 0; n > 1; n >> 1) ++k; return k; template <class RandomAccessIterator, class T, class Size> void __introsort_loop(RandomAccessIterator first, RandomAccessIterator last, T*, Size depth_limit) while(last - first > 16) if(depth_limit == 0) partial_sort(first, last, last); // 堆排序 return; --depth_limit; // 取中值 RandomAccessIterator cut = __unguarded_partition(first, last, T(_median( *first, *(first + (last - first) / 2), *(last - 1) ))); // 右半段递归sort __introsort_loop(cut, last, value_type(first), depth_limit); // 左半段在while中递归sort last = cut; template <class RandomAccessIterator> void __final_insertion_sort(RandomAccessIterator first, RandomAccessIterator last) if(last - first > 16) // 以下写法感觉有点冗余。先排序前16个数据,然后将后需要数据依次插入排序 __insertion_sort(first, first + 16); __unguarded_insertion_sort(first + 16, last); else // 小于16,直接插入排序 __insert_sort(first, last); template <class RandomAccessIterator> inline void __unguarded_insertion_sort(RandomAccessIterator first, RandomAccessIterator last) __unguarded_insertion_sort_aux(first, last, value_type(first)); template <class RandomAccessIterator, class T> void __unguarded_insertion_sort_aux(RandomAccessIterator first, RandomAccessIterator last, T*) for(RandomAccessIterator i = first; i != last; ++i) __unguarded_linear_insert(i, T(*i));
以上是关于STL源码剖析:算法的主要内容,如果未能解决你的问题,请参考以下文章