STL源码剖析学习十三:算法之基本算法

it2024-04-16  11

先给个实例:

#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"); }

 

 

 

如果第二序列的元素比第一序列的元素大,则多余的部分忽略不计。如果比第一序列的元素少,则会引发为定义行为

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); }

 

转载于:https://www.cnblogs.com/w0w0/archive/2012/04/26/2471211.html

最新回复(0)