C++标准库分析总结(九)——<算法>

目录

1 算法的形式

2 迭代器的分类(category)

2.1 各种容器的迭代器的iterator_category(迭代器的种类)

2.2 通过typeid()可以获取iterator_category

3 迭代器分类(category)对算法的影响的四个实例

3.1 distance

3.2 advance(和distance近似)

3.3 copy

3.4 destory(和copy近似,略)

3.5 迭代器的特殊情况_unique_copy

4 算法对迭代器中iterator_category的暗示

5 算法源代码剖析(11个例子)

5.1 如何判断是C的算法还是C++中的算法?

5.2 十一个算法实例

(1)accumulate()

(2)for_each()

(3)replace(), replace_if()和replace_copy()

(4)count()和count_if()

(5)find()和find_if()

(6)sort()

(7)binary_search()

6 算法实例





1 算法的形式

C++标椎库的算法,是什么东西?

  • 算法实际上看不到容器,它通过迭代器来进行运算算法通过询问迭代器(之前有说迭代器需要提供的五个相关类型)来完成自己的工作。
  • 算法在语言层面是是一个函数模板,具体是一个仿函数具有类似以下的格式:
template <typename Iterator>
std::Algorithm(Iterator itr1, Iterator itr2, ......)
{
    ......
}

2 迭代器的分类(category)

2.1 各种容器的迭代器的iterator_category(迭代器的种类)

一共有五种iterator_category,它们的关系如图所示:

iterator_category简述容器
forward_iterator_tag仅单向前进forward_list,unordered_set,unordered_map,unordered_multiset,unordered_multimap
bidirectional_iterator_tag双向,允许前进和后退list,set,map,multiset,multimap
random_access_iterator_tag允许访问随机下标array,vector,deque

另外有两种比较特殊,他们各自仅包含了一种迭代器

iterator_category包含的迭代器
input_iterator_tagistream_iterator
output_iterator_tagostream_iterator

2.2 通过typeid()可以获取iterator_category

//---------------------------------------------------
#include <iostream>     // std::cout
#include <iterator>     // std::iterator_traits
#include <typeinfo>     // typeid
namespace jj33
{
void _display_category(random_access_iterator_tag)
{   cout << "random_access_iterator" << endl; }
void _display_category(bidirectional_iterator_tag)
{   cout << "bidirectional_iterator" << endl; }
void _display_category(forward_iterator_tag)
{   cout << "forward_iterator" << endl;  }
void _display_category(output_iterator_tag)
{   cout << "output_iterator" << endl;   }
void _display_category(input_iterator_tag)
{   cout << "input_iterator" << endl;    }

template<typename I>
void display_category(I itr)
{
   typename iterator_traits<I>::iterator_category cagy;
   _display_category(cagy);
   
   cout << "typeid(itr).name()= " << typeid(itr).name() << endl << endl;   
       //The output depends on library implementation.
       //The particular representation pointed by the  
	   //returned valueis implementation-defined, 
	   //and may or may not be different for different types.   
}
	
void test_iterator_category()
{
	cout << "\ntest_iterator_category().......... \n";
  	
  	display_category(array<int,10>::iterator());
  	display_category(vector<int>::iterator());
  	display_category(list<int>::iterator());	
  	display_category(forward_list<int>::iterator());  
  	display_category(deque<int>::iterator());

  	display_category(set<int>::iterator());
  	display_category(map<int,int>::iterator());
  	display_category(multiset<int>::iterator());
  	display_category(multimap<int,int>::iterator());
  	display_category(unordered_set<int>::iterator());
  	display_category(unordered_map<int,int>::iterator());
  	display_category(unordered_multiset<int>::iterator());
  	display_category(unordered_multimap<int,int>::iterator());	  
	    	
  	display_category(istream_iterator<int>());
  	display_category(ostream_iterator<int>(cout,""));
}															 
}

可以注意到这些打印出来的iterator_category名称前后有一些无规律字符和数字,这些是编译器中的库实现方法决定的,编译器不同,这些数据也不同。但是实际上为了符合C++标准,它的实际类型都是一样的。

在这里插入图片描述

3 迭代器分类(category)对算法的影响的四个实例

3.1 distance

用来计算两个迭代器之间的距离。

在这里插入图片描述

3.2 advance(和distance近似)

和distance的做法基本相同,advance代表前进n步

在这里插入图片描述

3.3 copy

拷贝函数。

  • copy用了很多次泛化和特化,除了iterator traits以外还用了type traits
  • copy对其template参数所要求的条件非常宽松。其输入区间只需由inputIterators构成即可,输出区间只需要由OutputIterator构成即可。这意味着可以使用copy算法,将任何容器的任何一段区间的内容,复制到任何容器的任何一段区间上。

在这里插入图片描述

3.4 destory(和copy近似,略)

摧毁一个对象,调用析构函数。

在这里插入图片描述

3.5 迭代器的特殊情况_unique_copy

在这里插入图片描述

4 算法对迭代器中iterator_category的暗示

由于算法必须接受所有的迭代器,但是算法本身可以选择不对其进行处理。对于这些算法不想处理的迭代器,算法会在源代码中进行一些暗示
比如说这里就是特意修改了模板参数名,来暗示使用者这个算法的适用范围

在这里插入图片描述

5 算法源代码剖析(11个例子)

5.1 如何判断是C的算法还是C++中的算法

  • Q:如何判断是C的算法还是C++中的算法
  • A:首先C++的算法应该在标准库std中其次查看它的形参C++需要满足接受接受至少两个参数来表示迭代器

5.2 十一个算法实例

(1)accumulate()

accumulate()是累计函数,默认是加,也可以传入自定义操作.

template <class InputIterator,
          class T>
T accumulate(InputIterator first,
             InputIterator last,
             T init)
{
    for( ; first != last; ++first)
        // 将元素累加到初始值init身上
        init = init + *first;
    return init;
}
 
template <class InputIterator,
          class T,
          class BinaryOperation>
T accumulate(InputIterator first,
             InputIterator last,
             T init,
             BinaryOperation binary_op)
{
    for( ; first != last; ++first)
        // 将元素【累计算】到初始值init身上
        init = binary_op(init, *first);
    return init;
}

(2)for_each()

对一个范围内的元素做某种操作.

template <class InputIterator,
          class Function>
Function for_each(InputIterator first,
                  InputIterator last,
                  Function f)
{
    for( ; first != last; ++first)
        f(*first);
    return f;
}

该函数会返回一个值,但这个返回值会被忽略。还要注意不能通过迭代器修改元素的值,因为输入的是InputIterator,只读不能写。

(3)replace(), replace_if()和replace_copy()

  • replace() 算法会用新的值来替换和给定值相匹配的元素。它的前两个参数是被处理序列的正向迭代器,第 3 个参数是被替换的值,第 4 个参数是新的值。
  • replace_if() 将使谓词返回 true 的元素替换为新的值。它的第 3 个参数是一个谓词,第 4 个参数是新的值。参数的类型一般是元素类型的 const 引用;const 不是强制性的,但谓词不应该改变元素。
  • replace_copy() 算法和 replace() 做的事是一样的,但它的结果会被保存到另一个序列中,而不会改变原始序列。它的前两个参数是输入序列的正向迭代器,第 3 个参数是输入序列的开始迭代器,最后两个参数分别是要被替换的值和替换值。
template <class ForwardIterator, class T>
void replace(ForwardIterator first,
             ForwardIterator last,
             const T& old_value,
             const T& new_value){
    //范围内所有等同于old_value者都以new_value取代
    for(; first != last; ++first)
        if(*first == old_value)
            *first = new_value;
}
 
template <class ForwardIterator, class Predicate, class T>
void replace_if(ForwardIterator first,
                ForwardIterator last,
                Predicate pred,
                const T& new_value){
    //范围内所有满足pred()为true者都以new_value取代
    for(; first != last; ++first)
        if(pred(*first))
            *first = new_value;
}
 
template <class ForwardIterator, class OutputIterator, class T>
OutputIterator replace_copy(ForwardIterator first,
                            ForwardIterator last,
                            OutputIterator result,
                            const T& old_value,
                            const T& new_value){
    //范围内所有等同于old_value者都以new_value放到新区间,不符合者原值放到新区间
    for(; first != last; ++first, ++result)
        *result = 
            *first == old_value ? new_value : *first;
    return result;
}

(4)count()和count_if()

  • count函数统计元素个数,返回一个整形变量
  • count_if函数按条件统计元素个数
template <class InputIterator, class T>
typename iterator_traits<InputIterator>::difference_type
count(InputIterator first, InputIterator last,
      const T& value)
{
    typename iterator_traits<InputIterator>::difference_type n = 0;
    for(; first != last; ++first)
        if(*first == value)
            ++n;
    return n;
}
 
template <class InputIterator, class Predicate>
typename iterator_traits<InputIterator>::difference_type
count_if(InputIterator first, InputIterator last,
         Predicate pred)
{
    typename iterator_traits<InputIterator>::difference_type n = 0;
    for(; first != last; ++first)
        if(pred(*first))
            ++n;
    return n;
}

(5)find()和find_if()

  • find() 函数本质上是一个模板函数,用于在指定范围内查找和目标元素值相等的第一个元素
  • find_if() 函数和 find() 函数相同,find_if() 函数也用于在指定区域内执行查找操作。不同的是,前者需要明确指定要查找的元素的值,而后者则允许自定义查找规则
template <class InputIterator, class T>
InputIterator find(InputIterator first,
                   InputIterator last,
                   const T& value)
{
    while(first != last && *first != value)
        ++first;
    return first;
}
 
template <class InputIterator, class Predicate>
InputIterator find_if(InputIterator first,
                      InputIterator last,
                      Predicate pred)
{
    while(first != last && !pred(*first))
        ++first;
    return first;
}

(6)sort()

只介绍了sort()的用法。

#include <iostream>     // std::cout
#include <algorithm>    // std::sort
#include <vector>       // std::vector
namespace jj36
{
bool myfunc (int i,int j) { return (i<j); }

struct myclass {
  bool operator() (int i,int j) { return (i<j);}
} myobj;

bool test_sort()
{	
  cout << "\ntest_sort().......... \n";	

  int myints[] = {32,71,12,45,26,80,53,33};
  vector<int> myvec(myints, myints+8);          // 32 71 12 45 26 80 53 33

  // using default comparison (operator <):
  sort(myvec.begin(), myvec.begin()+4);         //(12 32 45 71)26 80 53 33

  // using function as comp
  sort(myvec.begin()+4, myvec.end(), myfunc); 	// 12 32 45 71(26 33 53 80)

  // using object as comp
  sort(myvec.begin(), myvec.end(), myobj);      //(12 26 32 33 45 53 71 80)

  // print out content:
  cout << "\nmyvec contains:";
  for (auto elem : myvec)		//C++11 range-based for statement
       cout << ' ' << elem ; 	//output: 12 26 32 33 45 53 71 80
       
  // using reverse iterators and default comparison (operator <):
  sort(myvec.rbegin(), myvec.rend());     
  
  // print out content:
  cout << "\nmyvec contains:";
  for (auto elem : myvec)		//C++11 range-based for statement
       cout << ' ' << elem ; 	//output: 80 71 53 45 33 32 26 12    
       
  // using explicitly default comparison (operator <):
  sort(myvec.begin(), myvec.end(), less<int>());  
  
  // print out content:
  cout << "\nmyvec contains:";
  for (auto elem : myvec)		//C++11 range-based for statement
       cout << ' ' << elem ; 	//output: 12 26 32 33 45 53 71 80   
	   
  // using another comparision criteria (operator >):
  sort(myvec.begin(), myvec.end(), greater<int>());  
  
  // print out content:
  cout << "\nmyvec contains:";
  for (auto elem : myvec)		//C++11 range-based for statement
       cout << ' ' << elem ; 	//output: 80 71 53 45 33 32 26 12 	        
}
}

逆向迭代器:

包含了一点rbegin()和rend()的内容,逆向迭代器的实现以后会讲。

(7)binary_search()

二分查找判断有序序列中是否存在某元素,内部工作是交给lower_bound()去做的。

template <class ForwardIterator, class T>
bool binary_search(ForwardIterator first,
                   ForwardIterator last,
                   const T& val)
{
    first = std::lower_bound(first, last, val);
    return (first != last && !(val < *first));
}
 
template <class ForwardIterator, class T>
ForwardIterator
lower_bound(ForwardIterator first,
            ForwardIterator last,
            const T& val)
{
    ForwardIterator it;
    iterator_traits<ForwardIterator>::difference_type count, step;
    count = distance(first, last);
    while(count > 0)
    {
        it = first; step = count / 2; advance(it, step);
        if(*it < val){
            first = ++it;
            count -= step + 1;
        }
        else count = step;
    }
    return first;
}

简单介绍一下lower_bound()和upper_bound()

  • 以从小到大排列的序列为例,lower_bound()返回的是第一个大于等于target的元素的位置,也就是第一个可以合法地插入target的位置;
  • upper_bound()返回的是第一个大于target的元素,也就是最后一个可以合法地插入target的位置。当然都可能出现target不存在的情况,这时返回的要么是begin()要么是end(),然后再进行一下和头元素或尾元素的大小判断就能知道target是否存在了。

在这里插入图片描述

6 算法实例

在这里插入图片描述

C++ STL常见算法2

C++ sort()排序函数用法详解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值