`
aspnetwinform
  • 浏览: 89835 次
  • 性别: Icon_minigender_2
  • 来自: 武汉
社区版块
存档分类
最新评论

从零开始学C++之STL(七):剩下5种算法代码分析与使用示例(remove 、rotate 、sort、lower_bound、accumulate)

 
阅读更多

一、移除性算法 (remove)

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br></nobr>
//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 会使当前迭代器失效,但可以返回下一个迭代器,故如果需要在遍历中删除,下面的做法才是正确的:


C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br></nobr>
#include<iostream>
#include<vector>

usingnamespacestd;

intmain(void)
{
inta[]={3,1,2,3,4};
vector<int>v(a,a+5);

//for(vector<int>::iteratorit=v.begin();it!=v.end();++it)
//{
//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<<endl;
return0;
}

示例代码1:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br></nobr>
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>
usingnamespacestd;

voidprint_element(intn)
{
cout<<n<<'';
}


intmain(void)
{
inta[]={1,3,2,3,4,5};
vector<int>v(a,a+6);

for_each(v.begin(),v.end(),print_element);
cout<<endl;

/*remove(v.begin(),v.end(),3);
for_each(v.begin(),v.end(),print_element);
cout<<endl;*/


v.erase(remove(v.begin(),v.end(),3),v.end());
for_each(v.begin(),v.end(),print_element);
cout<<endl;

return0;
}

二、变序性算法(rotate)

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br></nobr>
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 继续调用了某个函数,内部实现代码比较长,而且不容易看懂,这边可以看一下简易的等价


版本实现,来自这里,如下:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br></nobr>
template<classForwardIterator>
voidrotate(ForwardIteratorfirst,ForwardIteratormiddle,
ForwardIteratorlast)
{
ForwardIteratornext=middle;
while(first!=next)
{
swap(*first++,*next++);
if(next==last)next=middle;
elseif(first==middle)middle=next;
}
}

假设一个容器有 1 2 3 4 5 6 六个元素,现在想把 1 2 放到后面去,可以这样写rotate(v.begin(), v.begin()+2, v.end()); 如下图所示:


即将first 与 next 对应的元素互换且不断向前推进,直到first == next 为止。


三、排序算法 (sort)

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br></nobr>
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:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br></nobr>
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>
usingnamespacestd;

voidprint_element(intn)
{
cout<<n<<'';
}

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<<endl;

rotate(v.begin(),v.begin()+2,v.end());
for_each(v.begin(),v.end(),print_element);
cout<<endl;

sort(v.begin(),v.end());
for_each(v.begin(),v.end(),print_element);
cout<<endl;

sort(v.begin(),v.end(),my_greater);
for_each(v.begin(),v.end(),print_element);
cout<<endl;

return0;
}


四、已序区间算法 (lower_bound 、upper_bound)


使用这些算法的前提是区间已经是有序的。

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br></nobr>
//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 版本,如下:


C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br></nobr>
//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:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br></nobr>
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>
usingnamespacestd;

voidprint_element(intn)
{
cout<<n<<'';
}


intmain(void)
{
inta[]={1,10,10,14,15,16};
vector<int>v(a,a+6);

for_each(v.begin(),v.end(),print_element);
cout<<endl;

vector<int>::iteratorit;
it=lower_bound(v.begin(),v.end(),10);
if(it!=v.end())
{
cout<<it-v.begin()<<endl;
}

it=upper_bound(v.begin(),v.end(),10);
if(it!=v.end())
{
cout<<it-v.begin()<<endl;
}

return0;
}


五、数值算法(accumulate)


C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br></nobr>
//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:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br></nobr>
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>
#include<numeric>
usingnamespacestd;

voidprint_element(intn)
{
cout<<n<<'';
}

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<<endl;

//累加
cout<<accumulate(v.begin(),v.end(),0)<<endl;

//累乘
cout<<accumulate(v.begin(),v.end(),1,mult)<<endl;

return0;
}

参考:

C++ primer 第四版
Effective C++ 3rd
C++编程规范


分享到:
评论

相关推荐

    C++ STL--数据结构与算法实现(余文溪)示例程序代码.rar

    余文溪的《C++ STL--数据结构与算法实现》这本书很可能详细介绍了如何利用STL来解决实际问题,并通过示例程序代码来加深理解。 STL中的核心概念有以下几个: 1. 容器(Containers):这是STL的基础,它们是存储...

    c++ STL阐述了各种查找算法的异同以及使用他们的时机

    C++ STL 中提供了多种查找算法,每种算法都有其特点和使用场景,本文将对这些算法进行详细的介绍和比较。 首先,需要注意的是,STL 中的查找算法可以分为两组:A 组和 B 组。A 组包括 count 和 find,这两种算法不...

    lower-bound函数代码(C++实现).rar

    在给定的压缩包文件“lower_bound函数代码(C++实现).rar”中,可能包含了一个示例文档`.docx`,该文档可能详细解释了如何使用`lower_bound`函数,并提供了相关的代码实现和示例。通常,`lower_bound`的实现会基于...

    C++库函数及STL算法

    在C++编程中,库函数和STL(Standard Template Library,标准模板库)是不可或缺的组成部分,它们极大地提升了代码的效率和可读性。本文将深入探讨C++库函数和STL算法,以及如何在实际编程中应用这些概念。 首先,...

    C++ lower-bound()函数.docx

    虽然 C++ STL 没有提供 `lower_bound()` 函数的具体实现代码,但从其实现原理上来看,该函数采用了二分查找法来进行高效的查找。二分查找的时间复杂度为 O(log n),这意味着即使面对大规模数据集,该函数也能保持...

    c++标准库STL手册

    - **查找算法**:`find()`, `find_if()`, `lower_bound()`, `upper_bound()`等,用于在容器中查找特定元素或满足条件的元素。 - **交换和复制算法**:`swap()`, `copy()`等,用于元素的交换和容器之间的复制。 - ...

    lower-bound 的简要介绍.docx

    `lower_bound` 是 C++ STL 中非常重要的一个函数,它提供了一种高效的方式来定位有序序列中的元素。通过选择合适的版本和参数配置,可以灵活地满足不同的应用需求。无论是对于初学者还是资深开发者而言,掌握 `lower...

    stl的学习:c++ STL

    STL,全称为Standard Template Library(标准模板库),是C++编程语言中不可或缺的一部分,它为程序员提供了高效且可重用的数据结构和算法。STL的主要组成部分包括容器、迭代器、算法和函数对象,这些组件共同构成了...

    掌握C++ STL:深入理解与应用lower-bound函数.txt

    lower_bound函数

    C++STL目前可能最全的书籍和代码

    - 使用sort和lower_bound、upper_bound实现排序和二分查找。 - 利用函数对象自定义比较逻辑,如在排序中使用greater替代默认的less。 通过深入阅读书籍和实践代码,你可以掌握STL的精髓,提升编程效率,写出更高效...

    c++ SGI STL源代码学习

    SGI STL,全称为Stanford Graphics Group Standard Template Library,是由斯坦福大学图形小组开发的一套C++标准模板库,后来成为C++标准库的一部分。它为C++程序员提供了丰富的容器、迭代器、算法和函数对象,极大...

    从零开始学c++(ppt)

    《从零开始学C++》是一份专为初学者设计的教学资料,旨在引导学习者逐步掌握C++编程语言。这份教程包含丰富的基础知识讲解,搭配教案和源代码,使得学习过程更具实践性和互动性。 首先,从C++的基础部分开始,学习...

    C++ STL程序员面试题

    理解并熟练使用STL是C++程序员必备的技能之一,它能帮助编写出高效、可读性强的代码。在面试中,对STL的深入理解不仅可以展示你的技术实力,还能表现出你对编程最佳实践的追求。因此,熟悉STL的各个部分并能够灵活...

    深入理解C++ STL库:数据结构与算法的最佳实现.md

    探讨了C++标准模板库(STL)的核心组件和使用技巧,帮助读者深入理解如何高效地利用STL进行数据结构与算法的实现。文章首先介绍了STL的设计理念和核心组成部分,包括容器、迭代器、算法和函数对象。接着,逐一分析了...

    lower-bound-函数使用说明.pdf

    `lower_bound`经常与其他算法一起使用,比如`binary_search`等,以实现更高效的操作。例如,在一个排序的容器中快速查找一个元素是否存在: ```cpp bool exists = std::binary_search(v.begin(), v.end(), "cherry...

    C++&STL学习资料

    "C++_STL使用例子大全"可能会包含许多实际应用STL的实例,这些例子有助于理解STL在不同场景下的使用方式,例如如何使用vector来动态管理数组,如何使用map来建立关联关系,以及如何使用算法如sort进行排序操作。...

    STL算法备忘单+来自STL算法视频系列的示例代码_C++_下载.zip

    STL(Standard Template Library,标准模板库)是C++编程语言中的一个重要...结合备忘单和示例代码,开发者能更直观地理解每种算法的工作原理和应用场景。对于C++程序员来说,深入掌握STL是提高编程能力的关键一步。

    C++ STL开发技术导引(第5章)

    第5章 C++ STL泛化技术分析 58 5.1 算法和迭代器 58 5.1.1 算法 58 5.1.2 迭代器 61 5.1.3 函数对象 65 5.1.4 适配器 68 5.2 内存分配器和容器 74 5.2.1 内存分配器 75 5.2.2 容器 77 5.3 概念 ...

    C++ stl算法汇总(C++程序员必备)

    C++ STL(Standard Template Library,标准模板库)是C++编程中极其重要的组成部分,它提供了一组高效且灵活的算法,用于处理各种数据结构,如向量、列表、集合等。这些算法通常与容器(如vector、list)配合使用,...

Global site tag (gtag.js) - Google Analytics