一、移除性算法 (remove)
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
//TEMPLATEFUNCTIONremove_copy template< class_InIt, class_OutIt, class_Ty> inline _OutIt_Remove_copy(_InIt_First,_InIt_Last, _OutIt_Dest, const_Ty&_Val,_Range_checked_iterator_tag) { //copyomittingeachmatching_Val _DEBUG_RANGE(_First,_Last); _DEBUG_POINTER(_Dest); for(;_First!=_Last;++_First) if(!(*_First==_Val)) *_Dest++=*_First; return(_Dest); } template< class_InIt, class_OutIt, class_Ty> inline _OutItunchecked_remove_copy(_InIt_First,_InIt_Last, _OutIt_Dest, const_Ty&_Val) { //copyomittingeachmatching_Val return_STD_Remove_copy(_CHECKED_BASE(_First),_CHECKED_BASE(_Last),_Dest,_Val, _STD_Range_checked_iterator_tag()); } //TEMPLATEFUNCTIONremove template< class_FwdIt, class_Ty> inline _FwdItremove(_FwdIt_First,_FwdIt_Last, const_Ty&_Val) { //removeeachmatching_Val _First=find(_First,_Last,_Val); if(_First==_Last) return(_First); //emptysequence,alldone else { //nonemptysequence,worthdoing _FwdIt_First1=_First; return(_STDEXTunchecked_remove_copy(++_First1,_Last,_First,_Val)); } } |
如下图所示:
假设现在想要remove 的元素是3,则传入到_Remove_copy 函数的3个参数如上图第一行所示,Val 即3。
接着遍历First ~ Last 区间的元素,将非移除元素拷贝到前面,覆盖前面的元素,最后的指向如图,函数返回的是Dest 位置,如下代
码所示:
for(;_First!=_Last;++_First)
if(!(*_First==_Val))
*_Dest++=*_First;
由上图可看出移除性算法并没有改变元素的个数,如果要真正删除,可以将remove 的返回值传入erase 进行删除,如:
v.erase(remove(v.begin(), v.end(), 3), v.end()); 即会将后面两个元素4 和 5 删除掉。
在这里顺便提一下,erase 会使当前迭代器失效,但可以返回下一个迭代器,故如果需要在遍历中删除,下面的做法才是正确的:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include #include using namespacestd; intmain( void) { inta[]={ 3, 1, 2, 3, 4}; vector< int>v(a,a+ 5); //for(vector //if(*it==3) //v.erase(it);ERROR! //else //cout<<*it<<''; //} for(vector< int>::iteratorit=v.begin();it!=v.end();) { if(*it== 3) it=v.erase(it); else { cout<<*it<< ''; ++it; } } cout< } |
示例代码1:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include #include #include #include using namespacestd; voidprint_element( intn) { cout< } intmain( void) { inta[]={ 1, 3, 2, 3, 4, 5}; vector< int>v(a,a+ 6); for_each(v.begin(),v.end(),print_element); cout< /*remove(v.begin(),v.end(),3); for_each(v.begin(),v.end(),print_element); cout< v.erase(remove(v.begin(),v.end(), 3),v.end()); for_each(v.begin(),v.end(),print_element); cout< return 0; } |
2 3 4 5 6 7 |
template<
class_FwdIt>
inline
voidrotate(_FwdIt_First,_FwdIt_Mid,_FwdIt_Last) { //rotate[_First,_Last) if(_First!=_Mid&&_Mid!=_Last) _Rotate(_CHECKED_BASE(_First),_CHECKED_BASE(_Mid),_CHECKED_BASE(_Last),_Iter_cat(_First)); } |
rotate 调用了_Rotate,实际上_Rotate 继续调用了某个函数,内部实现代码比较长,而且不容易看懂,这边可以看一下简易的等价
版本实现,来自这里,如下:
2 3 4 5 6 7 8 9 10 11 12 |
template<
classForwardIterator>
voidrotate(ForwardIteratorfirst,ForwardIteratormiddle, ForwardIteratorlast) { ForwardIteratornext=middle; while(first!=next) { swap(*first++,*next++); if(next==last)next=middle; else if(first==middle)middle=next; } } |
假设一个容器有 1 2 3 4 5 6 六个元素,现在想把 1 2 放到后面去,可以这样写rotate(v.begin(), v.begin()+2, v.end()); 如下图所示:
即将first 与 next 对应的元素互换且不断向前推进,直到first == next 为止。
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
template<
class_RanIt>
inline
voidsort(_RanIt_First,_RanIt_Last) { //order[_First,_Last),usingoperator< _DEBUG_RANGE(_First,_Last); std::_Sort(_CHECKED_BASE(_First),_CHECKED_BASE(_Last),_Last-_First); } template< class_RanIt, class_Pr> inline voidsort(_RanIt_First,_RanIt_Last,_Pr_Pred) { //order[_First,_Last),using_Pred _DEBUG_RANGE(_First,_Last); _DEBUG_POINTER(_Pred); std::_Sort(_CHECKED_BASE(_First),_CHECKED_BASE(_Last),_Last-_First,_Pred); } |
sort 重载了两个版本,第一个版本只有2个参数,默认按从小到大排序(usingoperator<)
;第二个版本有三个参数,即可以自定义比较逻辑
(_Pred)。它们都调用了标准库的std::_Sort, 跟踪进去发现比较复杂,在_Sort 内会根据一些条件选择不同的排序方式,如标准库的堆排序,合并
排序,插入排序等等。站在使用的角度看,没必要去深究,但如果是想学习相关的排序,那是很好的资源。
示例代码2:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include #include #include #include using namespacestd; voidprint_element( intn) { cout< } boolmy_greater( inta, intb) { returna>b; } intmain( void) { inta[]={ 1, 2, 3, 4, 5, 6}; vector< int>v(a,a+ 6); for_each(v.begin(),v.end(),print_element); cout< rotate(v.begin(),v.begin()+ 2,v.end()); for_each(v.begin(),v.end(),print_element); cout< sort(v.begin(),v.end()); for_each(v.begin(),v.end(),print_element); cout< sort(v.begin(),v.end(),my_greater); for_each(v.begin(),v.end(),print_element); cout< return 0; } |
四、已序区间算法 (lower_bound 、upper_bound)
使用这些算法的前提是区间已经是有序的。
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
//TEMPLATEFUNCTIONlower_bound template< class_FwdIt, class_Ty, class_Diff> inline _FwdIt_Lower_bound(_FwdIt_First,_FwdIt_Last, const_Ty&_Val,_Diff*) { //findfirstelementnotbefore_Val,usingoperator< _DEBUG_ORDER_SINGLE(_First,_Last, true); _Diff_Count= 0; _Distance(_First,_Last,_Count); for(; 0<_Count;) { //divideandconquer,findhalfthatcontainsanswer _Diff_Count2=_Count/ 2; _FwdIt_Mid=_First; std::advance(_Mid,_Count2); _DEBUG_ORDER_SINGLE(_Mid,_Last, false); if(_DEBUG_LT(*_Mid,_Val)) _First=++_Mid,_Count-=_Count2+ 1; else _Count=_Count2; } return(_First); } template< class_FwdIt, class_Ty> inline _FwdItlower_bound(_FwdIt_First,_FwdIt_Last, const_Ty&_Val) { //findfirstelementnotbefore_Val,usingoperator< _ASSIGN_FROM_BASE(_First, _Lower_bound(_CHECKED_BASE(_First),_CHECKED_BASE(_Last),_Val,_Dist_type(_First))); return_First; } |
lower_bound() 返回第一个“大于等于给定值" 的元素位置,其实还重载了另一个low_bound 版本,如下:
2 3 4 5 6 7 |
//TEMPLATEFUNCTIONlower_boundWITHPRED template< class_FwdIt, class_Ty, class_Diff, class_Pr> inline _FwdIt_Lower_bound(_FwdIt_First,_FwdIt_Last, const_Ty&_Val,_Pr_Pred,_Diff*) |
也就是可以自定义比较逻辑,需要注意的是如果使用这个版本,那么区间应该本来就是按comp 方法排序的,如下面这句话:
The elements are compared usingoperator<
for the first version, andcompfor the second. The elements in the range shall already
besortedaccording to this same criterion (operator<
orcomp), or at leastpartitionedwith respect toval.
由于是已序区间,所以函数内用的是二分查找,而两个版本主要的代码不同在于:
_DEBUG_LT(*_Mid,_Val)
_DEBUG_LT_PRED(_Pred, *_Mid, _Val)
upper_bound 与 lower_bound 类似,不过返回的是第一个”大于给定值“ 的元素位置。
示例代码3:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#include #include #include #include using namespacestd; voidprint_element( intn) { cout< } intmain( void) { inta[]={ 1, 10, 10, 14, 15, 16}; vector< int>v(a,a+ 6); for_each(v.begin(),v.end(),print_element); cout< vector< int>::iteratorit; it=lower_bound(v.begin(),v.end(), 10); if(it!=v.end()) { cout< it=upper_bound(v.begin(),v.end(), 10); if(it!=v.end()) { cout< return 0; } |
五、数值算法(accumulate)
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
//TEMPLATEFUNCTIONaccumulate template< class_InIt, class_Ty> inline _Ty_Accumulate(_InIt_First,_InIt_Last,_Ty_Val) { //returnsumof_Valandallin[_First,_Last) _DEBUG_RANGE(_First,_Last); for(;_First!=_Last;++_First) _Val=_Val+*_First; return(_Val); } template< class_InIt, class_Ty> inline _Tyaccumulate(_InIt_First,_InIt_Last,_Ty_Val) { //returnsumof_Valandallin[_First,_Last) return_Accumulate(_CHECKED_BASE(_First),_CHECKED_BASE(_Last),_Val); } //TEMPLATEFUNCTIONaccumulateWITHBINOP template< class_InIt, class_Ty, class_Fn2> inline _Ty_Accumulate(_InIt_First,_InIt_Last,_Ty_Val,_Fn2_Func) { //returnsumof_Valandallin[_First,_Last),using_Func _DEBUG_RANGE(_First,_Last); _DEBUG_POINTER(_Func); for(;_First!=_Last;++_First) _Val=_Func(_Val,*_First); return(_Val); } template< class_InIt, class_Ty, class_Fn2> inline _Tyaccumulate(_InIt_First,_InIt_Last,_Ty_Val,_Fn2_Func) { //returnsumof_Valandallin[_First,_Last),using_Func return_Accumulate(_CHECKED_BASE(_First),_CHECKED_BASE(_Last),_Val,_Func); } |
accumulate 重载了两个版本,第一个版本实现的是累加,第二个版本带_Func 参数,可以自定义计算,比如累乘等。代码都比较好理解,就不赘述
了。看下面的示例代码4:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include #include #include #include #include using namespacestd; voidprint_element( intn) { cout< } intmult( inta, intb) { returna*b; } intmain( void) { inta[]={ 1, 2, 3, 4, 5}; vector< int>v(a,a+ 5); for_each(v.begin(),v.end(),print_element); cout< //累加 cout< //累乘 cout< return 0; } |
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范