STL常用算法大全

Aki 发布于 2023-03-16 333 次阅读


1、adjacent_find

该算法找出第一组满足条件的相邻元素。这里所谓的条件,在版本一中是指两个相邻元素相等;在版本二中允许用户指定一个二元运算,两个操作数分别是相邻的第一个和第二个元素。该算法会从first开始遍历到last,时间复杂度为O(logn)。

template<class ForwardIterator>
ForwardIterator adjacent_find(ForwardIterator first,ForwardIterator last);

template<class ForwardIterator,class BinaryPredicate>
ForwardIterator adjacent_find(ForwardIterator first,ForwardIterator last,BinaryPredicate op);


vector<int> v = {0,1,2,3,3,6,6,55,55};

//找出第一组相邻相等元素的第一个元素的索引
auto iter = adjacent_find(begin(v),end(v));
cout << distance(begin(v),iter) << endl;

//找出第一组相邻相等元素的第一个元素的索引,且该元素大于等于10       
iter = adjacent_find(begin(v),end(v),[](const int& x,const int& y){return x == y && x >= 10;});
cout << distance(begin(v),iter) << endl;   

2、count_if

将指定操作(一个仿函数)pred实施于[first,last)区间内的每一个元素身上,并将造成pred计算结果为true的所有元素个数返回。

template<class InputIterator,class Predicate>
size_t count_if(InputIterator first,InputIterator last,Predicate pred);

//统计v中元素大于0的元素个数
vector<int> v = {0,1,2,3};
size_t size = count_if(begin(v),end(v),[](const int& x){return x > 0;});
cout << size << endl;

3、find,find_if,find_end,find_first_of

find根据operator=运算符,顺序查找[first,last)区间内的每一个元素,找出第一个匹配的元素。如果找到就返回一个InputIterator指向该元素,否则返回last。

find_if根据指定的pred运算条件(以仿函数表示),顺序查找[first,last)区间内的每一个元素,找出第一个使pred为ture的元素。如果找到就返回一个InputIterator指向该元素,否则返回last。

find_end用于查找容器内子序列的最后一次出现。它在范围[first1,last1)中搜索由[first2,last2)定义的序列的最后一次出现,然后将迭代器返回到其第一个元素,如果没有发现,则返回last1。

find_first_of用于查找容器内子序列的第一次出现。它在范围[first1,last1)中搜索由[first2,last2)定义的序列的第一次出现,然后将迭代器返回到其第一个元素,如果没有发现,则返回last1。

template<class InputIterator,class T>
InputIterator find(InputIterator first,InputIterator last,const T& value);


template<class InputIterator,class Pred>
InputIterator find_if(InputIterator first,InputIterator last,Pred pred);


template<class ForwardIterator1,class ForwardIterator2>
ForwardIterator1 find_end (ForwardIterator1 first1, ForwardIterator1 last1,
ForwardIterator2 first2, ForwardIterator2 last2);

template<class ForwardIterator1,class ForwardIterator2>
ForwardIterator1 find_first_of (ForwardIterator1 first1, ForwardIterator1 last1,
ForwardIterator2 first2, ForwardIterator2 last2);


//在序列v中查找序列v1最后出现的位置
vector<int> v = {0,1,2,3,0,2,3,0,1,2,3,2,3,0,1,2,3};
vector<int> v1 = {0,1,2,3};         
auto iter = find_end(v.begin(),v.end(),v1.begin(),v1.end());
if(iter != v.end())
{      
      cout << distance(v.begin(),iter) << endl;                                                                
}

//在序列v中查找序列v1第一次出现的位置
iter = find_first_of(v.begin(),v.end(),v1.begin(),v1.end());                                                   
if(iter != v.end())
{
      cout << distance(v.begin(),iter) << endl;
}      

4、partition

partition会将区间[first,last)中的元素重新排列。所有被一元条件运算pred判定为true的元素都会被放在区间的前段;被判定为false的元素都会被放在区间的后段。这个算法并不保证保留元素的原始相对位置。如果需要保留原始相对位置,应该使用stable_partition。

template<class BidirectionalIterator,class Pred>
BidirectionalIterator partition(BidirectionalIterator first,BidirectionalIterator last,Pred pred);


//将所有为3的元素放到前面
vector<int> v = {0,1,2,3,0,2,3,0,1,2,3,2,3,0,1,2,3};
    
partition(v.begin(),v.end(),[](const int& x){return x == 3;});
   
ranges::for_each(v,[](const int& x){cout << x << "  ";});
cout << endl;

5、remove,remove_if(移除但不删除)

注意这一法则对于vector,array成立,对于list不成立!!!!

移除[first,last)之中所有与value相等的元素。这一算法并不真正从容器中删除哪些元素(换句话说容器的size并没有改变),而是将每一个不与value相等的元素轮番赋值给first之后的空间。返回值ForwardIterator标示出重新整理后的最后元素的下一个位置。这时可以利用成员函数erase删除掉该位置到尾迭代器位置的数据,这样的话就是真正的删除了。也提供了使用一元谓词的版本。

注意这两个算法不适用array,因为array无法缩小尺寸,导致残余数据永远存在。

template<class ForwardIterator,class T>
ForwardIterator remove(ForwardIterator first,ForwardIterator last,const T& value);


template<class ForwardIterator,class Pred>
ForwardIterator remove(ForwardIterator first,ForwardIterator last,Pred pred);


vector<int> v = {0,1,0,2,0,3,0,4};
  
cout << v.size() << endl;

auto iter = remove(v.begin(),v.end(),0);

v.erase(iter,v.end());
     
cout << v.size() << endl;
 
ranges::for_each(v,[](const int& x){cout << x << "  ";});

cout << endl;            

6、remove_copy,remove_copy_if

remove_copy和remove_copy_if作用与remove相同只不过生成的结果复制到另一个以result标识起始位置的容器身上。原容器没有任何改变。新容器可以和原容器重叠,但如果对新容器实际给值时超过了旧容器的大小那么会产生无法预期的效果。

template<class InputIterator,class OuputIterator,class T>
OuputIterator remove_copy(InputIterator first,InputIterator last,OuputIterator result,const T& val);


template<class InputIterator,class OuputIterator,class Pred>
OuputIterator remove_copy_if(InputIterator first,InputIterator last,OuputIterator result,Pred pred);



vector<int> v = {1,2,3,4,5,6,4,4},v1(v.size());
                                        
auto print = [](const int& x){cout << x << "  ";};
                                        
auto it = remove_copy(v.begin(),v.end(),v1.begin(),4);
                                        
for_each(v.begin(),v.end(),print);                                                                              
cout << endl;                     
                                        
for_each(v1.begin(),it,print);    
cout << endl;           

7、replace,replace_if,replace_copy,replace_copy_if

这个replace系列的函数将[first,last)区间内所有与old_value相等的值用new_value来替换。有接受一元谓词的if版本,有重定位输出的copy版本。

template<class ForwardIterator,class T>
void replace(ForwardIterator first,ForwardIterator last,const T& old_value,const T& new_value);


template<class ForwardIterator,class Pred,class T>
void replace_if(ForwardIterator first,ForwardIterator last,Pred pred,const T& new_value);


template<class InputIterator,class OuputIterator,class T>
void replace_copy(InputIterator first,InputIterator last,OuputIterator result,const T& old_value,const T& new_value);


template<class InputIterator,class OuputIterator,class T,class Pred>
void replace_copy_if(InputIterator first,InputIterator last,OuputIterator result,Pred pred,const T& new_value);



vector<int> v = {1,2,3,4,5,6,4,4},v1(v.size());                                                                 
auto print = [](const int& x){cout << x << "  ";};                                                              
replace_copy_if(v.begin(),v.end(),v1.begin(),[](const int& x){return x == 4;},10);                              
for_each(v.begin(),v.end(),print);                                                                              
cout << endl;                                                                                                   
for_each(v1.begin(),v1.end(),print);                                                                            
cout << endl;                                                                                                   
      

8、lower_bound,upper_bound,equal_range,binary_search(二分查找)

这四个算法要求必须是有序区间!!!

binary_search是最简单的二分查找,它的返回值是bool,无法提供能够利用的信息,如该元素的索引位置,它只能告诉你该元素是否存在!!!

template<class ForwardIterator,class T>
bool binary_search(ForwardIterator first,ForwardIterator last,const T& val);

lower_bound试图在已排序的区间[first,last)中寻找元素value。如果区间中存在该元素,则返回一个迭代器指向其中第一个元素。如果没有找到该元素,则返回 “假设该元素存在时应该出现的位置” 的迭代器。也就是说会返回一个迭代器指向第一个不大于value的元素。如果value大于区间内所有的元素,则返回last。

upper_bound作用是lower_bound相同,不过它返回的是最后一个元素出现的位置的下一个位置!!!

这两个函数都有接受一元谓词的版本,重载了第三个参数!!!这两个函数都不能用来精确的二分查找!!因为如果目标元素存在那么可以使用lower_bound来得到正确的结果;如果不存在那么这两个函数都不保证返回正确的结果!!!所以就需要使用equal_range!!!

template<class ForwardIterator,class T>
ForwardIterator lower_bound(ForwardIterator first,ForwardIterator last,const T& value);


vector<int> v = {1,2,3,4,4,4,5,6,7};                                                                            
                                                                                                                      
                                                      
//4第一次出现的位置是3,最后一次出现的位置是5,所以返回3                                                                                                                   
auto it = lower_bound(v.begin(),v.end(),4);   
cout << distance(v.begin(),it) << endl;   

//返回5+1
it = upper_bound(v.begin(),v.end(),4);                                                                          
cout << distance(v.begin(),it) << endl;   

equal_range也是二分查找的一种。该算法试图在已排序区间[first,last)中寻找value。返回值是一个pair类型,first和second都是迭代器。其中first的lower_bound的结果,second是upper_bound的结果!!!

如果区间内没有value元素,这种情况下返回的两个迭代器形成了一个空区间。这个条件非常重要,因为可以用来进行精确的二分查找了!!!

template<class ForwardIterator,class T>
pair<ForwardIterator,ForwardIterator> equal_range(ForwardIterator first,ForwardIterator last,const T& value);

vector<int> v = {1,2,3,4,4,4,5,6,7};   
                                                                                       
auto it = equal_range(v.begin(),v.end(),500);                                                                   
 
//判断是否存在该元素!!!存在就打印出第一个该元素的索引                                     
if(it.first != it.second)              
{                                      
        cout << distance(v.begin(),it.first) << endl; 
}                

9、reverse,reverse_copy

这两个算法将序列[first,last)内的元素颠倒重排。copy版本的重定位了输出,且对原容器的元素不会造成改变。

template<class BidirectionalIterator>
void reverse(BidirectionalIterator first,BidirectionalIterator last);


template<class BidirectionalIterator,class OuputIterator>
void reverse_copy(BidirectionalIterator first,BidirectionalIterator last,OuputIterator result);



vector<int> v = {1,2,3,4,4,4,5,6,7},v1(v.size());                                                                
auto print = [](const int& x){cout << x << "  ";};                                                                                                                                             
for_each(v.begin(),v.end(),print);                                                                              
cout << endl;                                                                                                    reverse_copy(v.begin(),v.end(),v1.begin());                                                                     
for_each(v1.begin(),v1.end(),print);                                                                            
cout << endl;           

10、rotate,rotate_copy

该算法将[first,middle)内的元素和[middle,last)内的元素交换。middle指向的第一个元素会变成容器的第一个元素。如果有个序列(1,2,3,4,5,6,7),执行middle为3的时交换后变成(3,4,5,6,7,1,2)。功能和swap_range()类似,但是swap_range只能交换两个长度相同的区间,这个可以交换不相同的区间。copy版本重定位了输出,新产生出来的序列被置于result所指的容器的开始位置,且原容器的内容不变,返回值指向新序列的最后一个元素。

template<class ForwardIterator>
void rotate(ForwardIterator first,ForwardIterator middle,ForwardIterator last);


template<class ForwardIterator,class OuputIterator>
OuputIterator rotate_copy(ForwardIterator first,ForwardIterator middle, ForwardIterator last,OuputIterator result);


vector<int> v = {1,2,3,4,5,6,7},v1(v.size());                                                                   
    
auto print = [](const int& x){cout << x << "  ";};                                                              
    
for_each(v.begin(),v.end(),print);                                                                              
cout << endl;                                                                                                   
     
auto it = equal_range(v.begin(),v.end(),3);                                                                     
     
rotate_copy(v.begin(),it.first,v.end(),v1.begin());                                                             
for_each(v1.begin(),v1.end(),print);                                                                            
cout << endl;                  

11、for_each,transform

for_each算法会遍历给定的容器,并对每个元素执行指定的操作。其中,firstlast是表示要遍历的容器的迭代器范围,f是要执行的操作的函数对象。for_each算法将对[first,last)范围内的每个元素,调用函数对象f,该函数对象接受一个元素作为参数,并将对该元素执行所需的任何操作。for_each算法最终会返回传递给它的函数对象f的副本。

transform算法与for_each类似,但它会遍历一个容器,并对每个元素执行某些转换操作,然后将结果存储在另一个容器中。其中,first1last1是表示要遍历的输入容器的迭代器范围,d_first是表示要存储结果的输出容器的起始迭代器,unary_op是要执行的转换操作的函数对象。transform算法将对[first1,last1)范围内的每个元素调用函数对象unary_op,该函数对象接受一个元素作为参数,并将对该元素执行所需的任何操作。然后,它将转换后的结果存储在d_first指向的输出容器中,并返回输出容器中最后一个被修改元素的下一个位置的迭代器。

for_each算法用于遍历并对一个容器中的每个元素执行指定的操作,而transform算法用于遍历一个输入容器,并将每个元素转换成新的元素,然后将结果存储在一个输出容器中。

template <typename InputIt, typename UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f);


template <typename InputIt, typename OutputIt, typename UnaryOperation>
OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first, UnaryOperation unary_op);

12、merge,inplace_merge

mergeinplace_merge都是用于合并两个已排序的容器的算法。

merge将两个经过排序的集合S1和S2合并起来置于另一个空间上。所得到的序列也是一个有序的序列,返回一个迭代器,指向结果序列最后一个位置的下一个位置。

template <typename InputIt1, typename InputIt2, typename OutputIt>
OutputIt merge(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first);

inplace_merge算法也是用于合并两个已排序的容器,但它会将结果存储在原始容器中,而不是在另一个容器中。利用inplace_merge来实现归并排序非常的简单!!!

template <typename BidirIt>
void inplace_merge(BidirIt first, BidirIt middle, BidirIt last);



template<class InputIterator>                                                                                         
void merge_sort(InputIterator first,InputIterator last) noexcept                                                      
{                                                                                                                     
       size_t n = distance(first,last);                                                                                
       if(n < 2)                                                                                                       
       {                                                                                                               
             return;                                                                                                   
       }                                                                                                               
       InputIterator mid = first + n / 2;                                                                              
       merge_sort(first,mid);                                                                                          
       merge_sort(mid,last);                                                                                           
       inplace_merge(first,mid,last);                                                                                  
}                                                                                                                     
   

merge算法用于将两个已排序的容器合并成一个有序的容器,并将结果存储在另一个容器中,而inplace_merge算法用于将两个已排序的容器合并成一个有序的容器,并将结果存储在原始容器中,以便原始容器中的元素保持有序。