STL源码剖析学习十三:算法之基本算法
2012-04-26 12:48
417 查看
先给个实例:
![](file:///C:/Documents%20and%20Settings/Administrator/Application%20Data/Tencent/Users/675089985/QQ/WinTemp/RichOle/I%}`}5LL}~L0D3SN{}A98_4.jpg)
如果第二序列的元素比第一序列的元素大,则多余的部分忽略不计。
如果比第一序列的元素少,则会引发为定义行为
将区间内前n个元素改为新值,返回的迭代器指向被填入元素的最后一个元素的下一个位置
如果n超越了容器现有的大小,会造成不可预期的行为,解决方法是把改写操作改成插入操作
fill_n(inserter(iv, iv.begin()), 5, 7);
从begin位置开始插入5个值为7的元素
将两个迭代器所指的对象对调
函数必须知道迭代器的value type 才能够声明一个对象tmp
设计双层构造,多了一个额外的参数value_type(a)
也可以写成:
以字典排列方式对两个容器内的元素进行比较
平行比较两个序列,找出第一个不匹配点,返回一对迭代器
如果第二个序列比第一个序列的元素多,多出来的忽略不计,如果少,则可能引发未定义的行为
copy为了提高效率采用了各种方法,函数重载,型别特性,偏特化等
如果copy的输入区间和输出区间没有重叠,则没有问题,但是如果有重叠,则可能出现问题
只有当底层调用的函数为memmove时不会出现问题,因为他把所有区间先复制下来,不会出现区间被改写的问题
copy能为输出区间内的元素赋予新值,而不是产生新的元素,不能改变输出迭代器中的元素的个数。
如果需要向输出区间中插入元素,则需要用copy算法搭配insert_iterator
完全泛化版本:
重载函数:
针对原生指针,const char*和const wchar_t*,直接进行内存拷贝操作。
wchar_t版本同理
__copy_dispatch有一个完全泛化版本和两个偏特化版本
偏特化版本
对于has_trival_assignment_operator不懂,下面是一种解释:
trivial的c++ class
就像是C语言里面的struct一样,就是自己没有虚函数表,自己的基类和成员都没有,
它的拷贝复制都只需要简单的逐位拷贝就行了
non-trivial class
是C++特有的,和C的struct有明显的区别,它的拷贝需要特殊处理,因为有虚函数表的存在
__copy_dispatch()根据迭代器的不同,调用不同的__copy()
InputIterator版本
RandomAccessIterator版本
又划分出一个函数,为了重用
trival_assignment_operator 平凡的赋值操作符
如果指针所指对象拥有non_trival_assignment_operator,复制操作必须通过它来进行
但是如果指针所指对象拥有的是trival_assignment_operator
复制操作可以不通过它,直接用内存拷贝方式进行就可以
C++本身不能探测到某个对象是否拥有trival_assignment_operator,
可以通过__type_traits<>方法来弥补
通过增加间接层的方法对__copy_dispatch进行偏特化,衍生出两个__copy_t()
所指对象拥有trival_assignment_operator
所指对象拥有non_trival_assignment_operator
#include<iostream> #include<numeric> #include<vector> #include<algorithm> #include<functional> #include<iterator> #include<string> using namespace std; template <class T> struct display { void operator()(const T& x) const { cout<<x<<" "; } }; int main() { int ia[9] = {0,1,2,3,4,5,6,7,8}; vector<int> iv1(ia, ia+5); vector<int> iv2(ia, ia+9); pair<vector<int>::iterator,vector<int>::iterator> p = mismatch(iv1.begin(), iv1.end(), iv2.begin()); if(p.first == iv1.end()) cout<<"iv1.end"<<endl; else cout<<*(p.first)<<endl; if(p.second == iv2.end()) cout<<"iv2.end"<<endl; else cout<<*(p.second)<<endl; cout<<equal(iv1.begin(), iv1.end(), iv2.begin())<<endl; cout<<equal(iv1.begin(), iv1.end(), &ia[3])<<endl; cout<<equal(iv1.begin(), iv1.end(), &ia[3], less<int>())<<endl; fill(iv1.begin(), iv1.end(), 9); for_each(iv1.begin(), iv1.end(), display<int>()); cout<<endl; fill_n(iv1.begin(), 3, 7); for_each(iv1.begin(), iv1.end(), display<int>()); cout<<endl; vector<int>::iterator ite1 = iv1.begin(); vector<int>::iterator ite2 = ite1; advance(ite2, 3); iter_swap(ite1, ite2); cout<<*ite1<<" "<<*ite2<<endl; for_each(iv1.begin(), iv1.end(), display<int>()); cout<<endl; cout<<max(*ite1, *ite2)<<endl; cout<<min(*ite1, *ite2)<<endl; swap(*iv1.begin(), *iv2.begin()); for_each(iv1.begin(), iv1.end(), display<int>()); cout<<endl; for_each(iv2.begin(), iv2.end(), display<int>()); cout<<endl; string stra1[] = {"jamie", "jjhou", "jason"}; string stra2[] = {"jamie", "jjhou", "jerry"}; cout<<lexicographical_compare(stra1, stra1+3, stra2, stra2+3)<<endl; cout<<lexicographical_compare(stra1, stra1+3, stra2, stra2+3, greater<string>())<<endl; fill_n(inserter(iv1, iv1.begin()), 20, 3); for_each(iv1.begin(), iv1.end(), display<int>()); cout<<endl; system("pause"); }
![](file:///C:/Documents%20and%20Settings/Administrator/Application%20Data/Tencent/Users/675089985/QQ/WinTemp/RichOle/I%}`}5LL}~L0D3SN{}A98_4.jpg)
如果第二序列的元素比第一序列的元素大,则多余的部分忽略不计。
如果比第一序列的元素少,则会引发为定义行为
equal(first1, last1, first2) { for(; first1!=last1; ++first1, ++first2) if(*first1 != *first2) return false; return true; }
将区间内前n个元素改为新值,返回的迭代器指向被填入元素的最后一个元素的下一个位置
fill_n(first, n, value) { for(; n>0; --n,first) { *first = value; } return first; }
如果n超越了容器现有的大小,会造成不可预期的行为,解决方法是把改写操作改成插入操作
fill_n(inserter(iv, iv.begin()), 5, 7);
从begin位置开始插入5个值为7的元素
将两个迭代器所指的对象对调
iter_swap(a, b) { __iter_swap(a, b, value_type(a)); } __iter_swap(a, b, T*) { T tmp = *a; *a = *b; *b = tmp; }
函数必须知道迭代器的value type 才能够声明一个对象tmp
设计双层构造,多了一个额外的参数value_type(a)
也可以写成:
iter_swap(ForwardIterator1 a, ForwardIterator2 b) { typename iterator_traits<ForwardIterator1>::value_type tmp = *a; *a = *b; *b = tmp; }
以字典排列方式对两个容器内的元素进行比较
lexicographical_compare { for(; first1!=last1 && firs2!=last2; ++first1, ++first2) { if(*first1 < *first2) return true; if(*first2 < *first1) return false; } return first1 == last1 && first2 != last2; }
平行比较两个序列,找出第一个不匹配点,返回一对迭代器
如果第二个序列比第一个序列的元素多,多出来的忽略不计,如果少,则可能引发未定义的行为
mismatch(first1, last1, first2) { while(first!=last1 && *first1==*first2) { ++first1; ++first2; } return pair<InputIterator1, InputIterator2>(first1, first2); }
copy为了提高效率采用了各种方法,函数重载,型别特性,偏特化等
如果copy的输入区间和输出区间没有重叠,则没有问题,但是如果有重叠,则可能出现问题
只有当底层调用的函数为memmove时不会出现问题,因为他把所有区间先复制下来,不会出现区间被改写的问题
copy能为输出区间内的元素赋予新值,而不是产生新的元素,不能改变输出迭代器中的元素的个数。
如果需要向输出区间中插入元素,则需要用copy算法搭配insert_iterator
完全泛化版本:
copy(InputIterator first, InputIterator last, OutputIterator result) { return __copy_dispatch<InputIterator, OutputIterator>()(first, last, result); }
重载函数:
针对原生指针,const char*和const wchar_t*,直接进行内存拷贝操作。
incline char* copy(const char* first, const char* last, char* result) { memmove(result, first, last-first); return result+(last-first); }
wchar_t版本同理
incline 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); }
__copy_dispatch有一个完全泛化版本和两个偏特化版本
template<class InputIterator, class OutputIterator> struct __copy_dispatch { OutputIterator operator(InputIterator first, InputIterator last, OutputIterator result) { 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(first, last, result, t()); } } template<class T> struct __copy_dispatch<const T*, T*>
对于has_trival_assignment_operator不懂,下面是一种解释:
trivial的c++ class
就像是C语言里面的struct一样,就是自己没有虚函数表,自己的基类和成员都没有,
它的拷贝复制都只需要简单的逐位拷贝就行了
non-trivial class
是C++特有的,和C的struct有明显的区别,它的拷贝需要特殊处理,因为有虚函数表的存在
__copy_dispatch()根据迭代器的不同,调用不同的__copy()
InputIterator版本
__copy(InputIterator first, InputIterator last, OutputIterator result, input_iterator_tag) { for(; first!=last; ++result, ++first) *result = *first; return result; }
RandomAccessIterator版本
__copy(RandomAccessIterator first, RandomAccessIterator last, OutputIterator result, random_access_iterator_tag) { return __copy_d(first, last, result, distance_type(first)); }
又划分出一个函数,为了重用
__copy_d(RandomAccessIterator first, RandomAccessIterator last, OutputIterator result, Distance*) { for(Distance n = last-first; n>0; --n,++result,++first) *result = *first; return result; }
trival_assignment_operator 平凡的赋值操作符
如果指针所指对象拥有non_trival_assignment_operator,复制操作必须通过它来进行
但是如果指针所指对象拥有的是trival_assignment_operator
复制操作可以不通过它,直接用内存拷贝方式进行就可以
C++本身不能探测到某个对象是否拥有trival_assignment_operator,
可以通过__type_traits<>方法来弥补
通过增加间接层的方法对__copy_dispatch进行偏特化,衍生出两个__copy_t()
所指对象拥有trival_assignment_operator
template<class T> incline T* __copy_t(const T* first, const T* last, T* result, __true_type) { memmove(result, first, sizeof(T),*(last-first)); return result+(last-first); }
所指对象拥有non_trival_assignment_operator
template<class T> incline T* __copy_t(const T* first, const T* last, T* result, __false_type) { return __copy_d(first, last, result, (ptrdiff_f*)0); }
相关文章推荐
- STL源码剖析学习之基本算法
- STL源码剖析学习十六:算法之其他算法
- STL源码剖析学习十四:算法之set相关算法
- STL源码剖析学习之数值算法
- 算法导论学习笔记(16)——图的基本算法
- 算法学习入门之使用C语言实现各大基本的排序算法
- x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*()
- STL源码剖析——STL算法之sort排序算法
- 【算法学习】——基本数据结构
- STL源码剖析 [算法](一)[stl_numeric.h]==>copy
- 监督学习的基本思想及最基本算法——梯度下降
- java学习个人笔记---内存管理之垃圾回收基本算法
- 算法导论学习笔记-第二十二章-图的基本算法
- STL源码剖析学习十七:算法之其他算法
- 【转】 ACM基本算法分类、推荐学习资料和配套pku习题
- C++ STL源码学习(基本算法篇)
- java之jvm学习笔记十三(jvm基本结构)
- 网络层概念学习之一(基本概念、路由器、选路算法)
- 基本算法学习(一)—— 排序
- 【直观梳理深度学习关键概念】优化算法、调参基本思路、正则化方式等