本文记录STL常用的算法,遍历算法,查找算法, 排序算法,替换算法,算数生成算法等。 这里这些知识点时,参考了一篇公众号上的文章。

8.6 算法简介、部处理与使用范例

8.6.1算法简介

算法就是全局的函数,每个容器有自己的成员函数,而算法就是全局函数。
容器要想使用算法,通过迭代器给算法传递位置。而传递是前闭后开的区间,因为不包含最后一个位置。判断空区间:beginiter = enditer.
所以,算法是搭配迭代器使用的全局函数。

8.6.2算法内部处理

使用算法时,需要给算法传递迭代器。

8.6.3 STL模板库算法

8.6.3.1 STL标准库模板算法

掌握了STL算法,就相当于掌握了一把开启了C++高性能编程的钥匙。
STL算法头文件:,包含了各种常用的算法函数,如比较,交换,查找,遍历,复制,修改,排序、查找、变换等。
在项目中,能使用STL算法就减少使用for循环来自己写。
下面对算法进行了分类。

8.6.3.2 常用遍历算法
1 for_each 遍历算法

作用:对指定范围内的每一个元素执行指定的操作。
源码如下:

    template<typename InputIterator,typename Function>
    Function for_each(InputIterator first, InputIterator last, Function f)
    {
        for (; first != last; ++first)
        {
            f(*first); // 调用函数对象f,传入当前元素
        }
        return f; // 返回函数对象f
	}

参数:InputIterator first, InputIterator last 分别是单项输入型迭代器的起始和结束位置,Function f 是可调用对象,即可以是函数对象,函数指针或lambda表达式,这个函数对象可以接受一个参数,对这个参数进行操作。for_each遍历前闭后开区间[first, last),对每个元素执行函数f。
返回值:返回传入的函数对象f,通常用于链式调用或获取最终结果。如果传入的是一个带有状态的函数对象,那么可以通过返回值来获取最终的状态。
使用场景:打印容器中所有元素;
修改容器中所有元素,注意:如果要修改元素的值,必须使用引用 & ,否则修改的元素的拷贝,而不是元素元素。
优点:for_each 比传统的for循环更简洁,尤其是在配合lambda表达式时。
性能优于传统的for循环,因为进行高度优化;
注意:不要在for中修改容器结构,即不要插入和删除元素,否则迭代器失效。
例子1:遍历数组,统计大于某个阈值的元素数量。

    class Counter
    {
    public:

        void operator()(int& n)
        {
            if (n > m_threshhold)
            {
                m_count++;
            }
        }

        int get_count() const
        {
            return m_count;
        }

    private:
        int m_threshhold = 3;
        int m_count = 0;
    };

    void test()
    {
        vector<int> numbers{ 1,2,3,4,5 };
        Counter counter; // 2
        counter = std::for_each(numbers.begin(), numbers.end(), counter);

        cout << "大于3的元素数量:" << counter.get_count() << endl;
    }

2 transform算法

std::transform对一个或多个输入序列元素应用一个操作,并将结果保存到另一个序列中。
std::transform有两个重载版本:
重载版本1:对一个输入序列进行操作:

template<typename InputIterator,typename OutputIterator,typename UnaryOperation>
OutputIterator transform(InputIterator first1, InputIterator last1,OutputIterator result, UnaryOperation op);

参数:
first1, last1: 定义输入序列的起始和结束迭代器。
result: 指向输出序列的起始位置的迭代器。输出序列必须有足够的空间来存储结果。
op: 一个一元函数对象 (函数、函数指针、Lambda 表达式或重载了 operator() 的类),它接受一个输入序列的元素作为参数,并返回转换后的值。
函数作用:std::transform 对 [first1, last1) 范围内的每个元素应用 op 函数对象,并将结果存储到以 result 开始的输出序列中。
重载版本2:(二元变换):

template <class InputIterator1, class InputIterator2, class OutputIterator, class BinaryOperation>
 OutputIterator transform (InputIterator1 first1, InputIterator1 last1,InputIterator2 first2,OutputIterator result, BinaryOperation binary_op);

参数:
first1, last1: 定义第一个输入序列的起始和结束迭代器。
first2: 定义第二个输入序列的起始迭代器。 第二个输入序列至少要有 last1 - first1 个元素。
result: 指向输出序列的起始位置的迭代器。 输出序列必须有足够的空间来存储结果。
binary_op: 一个二元函数对象,接受两个输入序列的元素作为参数 (一个来自第一个序列,一个来自第二个序列),并返回转换后的值。
函数作用: std::transform 同时遍历 [first1, last1) 范围内的第一个序列和以 first2 开始的第二个序列。 对于每个对应的元素对,应用 binary_op 函数对象,并将结果存储到以 result 开始的输出序列中。
返回值: 两个版本都返回一个迭代器,指向输出序列中最后一个写入元素的下一个位置(即,超出最后一个写入元素的位置)。
使用场景总结:
 当需要对容器中每个元素指向相同操作;
 当需要原地修改一个容器时;
 当需要对两个容器的元素进行某种操作时
示例 1: 一元变换 - 求 vector 中的每个元素平方

  void test2()
   {
       vector<int> number1{ 1,2,3,4,5 };
       vector<int> result{}; // 这个result大小比如大于等于number数组大小,否则出现未定义行为

       // 1 使用 transform 将每个元素平方,并将结果保存在result中
       std::transform(number1.begin(), number1.end(), std::back_inserter(result),
           [](int x) {
               return x * x;
           });
       cout << "转换后:" << endl;
       for (int v : result)
       {
           cout << v << "  ";
       }
       cout << endl;
       // 1  4  9  16  25

       vector<int> result2(number1.size(),0); 
       // 使用 transform 将每个元素平方,并将结果保存在result中
       std::transform(number1.begin(), number1.end(), std::back_inserter(result2), // 在最后插入 
           [](int x) {
               return x * x;
           });
       // 输出 result2,可以使用
       for (int v : result2)
       {
           cout << v << "  ";
       }
       // 0  0  0  0  0  1  4  9  16  25
       cout << endl;

       vector<int> result3;
       result3.reserve(5);  // 可以对其进行预分配,单不能直接定义大小
       // 使用 transform 将每个元素平方,并将结果保存在result中
       std::transform(number1.begin(), number1.end(), std::back_inserter(result3),
           [](int x) {
               return x * x;
           });
       for (int v : result3)
       {
           cout << v << "  ";
       }
       // 1  4  9  16  25
       cout << endl;
            
   }

结论总结:
在使用transform时,接收结果的result可以使用reserve预定义大小,但是不能直接resize()大小,否则插入到了resize()后边。对于传入的结果容器,要使用 std::back_inserter(result) 自动扩展输出容器的大小,或者提前分配好足够的空间。

示例 2: 二元变换 - 将两个 vector 的对应元素相加,结果放在容器sums中
同时操作两个容器的数据, 进行操作后,放在第三个容器中。

void test3()
 {
     std::vector<int> numbers1 = { 1, 2, 3, 4, 5 };
     std::vector<int> numbers2 = { 5, 4, 3, 2, 1 };
     std::vector<int> result;

     std::transform(numbers1.begin(), numbers1.end(), numbers2.begin(), std::back_inserter(result),
         [](int x, int y) {  // Lambda表达式作为函数对象, BinaryOperation 
             return x + y;
         });
     for (int v : result)
     {
         cout << v << "  ";
     }
     std::cout << std::endl; 
     // 输出: Sums: 6 6 6 6 6
 }

实例3:原地变换,即不使用额外数组存放结果
将容器中的每个元素 *2。

void test4()
 {
     vector<int> number{ 1,2,3,4,5 };

     std::transform( number.begin(), number.end(), number.begin(), [](int x) {
         return x * 2;
     });

     for (int v : number)
     {
         cout << v << "  ";
     }
     std::cout << std::endl;
     // 2  4  6  8  10
     return;
}

8.6.3.3 常用查找算法
1 find算法

std::find 算法是 C++ STL 中用于在一个范围内查找特定值的算法。
函数原型:

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

参数:
first last,定义要搜索的范围的起始和结束迭代器,搜索范围[first,end),前闭后开。
val :要查找的值,类型必须与 InputIterator 解引用后的值类型相同。
作用:std::find 算法在 [first, last) 范围内查找等于 val 的第一个元素。
返回值:
如果找到等于 val 的元素,则返回指向该元素的迭代器。
如果未找到任何等于 val 的元素,则返回 last 迭代器。
最后,可以通过返回值是否等于end()来判断。
迭代器类型:InputIterator 可以是任何输入迭代器类型,例如,来自 std::vector, std::list, std::array, C 风格数组等的迭代器。
算法原理:std::find 使用 == 运算符来比较元素。如果要在自定义类型上使用 std::find,确保为该类型重载了 == 运算符。
std::find 是一个线性搜索算法,需要遍历整个范围,直到找到目标元素或到达范围的末尾,在大型容器中,这会比较慢。
对于需要频繁搜索的场景,可以考虑使用其他数据结构和算法,例如,std::set, std::map, 或哈希表。
示例1:查找Number中的元素

  void test()
  {
      vector<int> numbers = { 1,2,3,4,5 };
      auto it = find(numbers.begin(), numbers.end(), 3);
      if (it != numbers.end())
      {
          cout << "找到了" << endl;
          int index = std::distance(numbers.begin(), it);
          cout << "index = " << index << endl;
          // index = 2
      }
      else
      {
          cout << "未找到" << endl;
      }
  }

示例2:查找自定义类型的元素
查找自定义类型的元素值,需要在类中重载operator==运算符。

    class MyValue
    {
    public:
        MyValue(int value):m_value(value)
        {
        }

        // 重载 operator==
        bool operator==(const MyValue& other) const
        {
            return m_value == other.m_value;
        }
        int getValue()
        {
            return m_value;
        }
    private:
        int m_value;
    };

    void test2()
    {
        vector<MyValue> objs;
        objs.emplace_back(10);
        objs.emplace_back(20);
        objs.emplace_back(30);
        MyValue target(20);
        auto it = std::find(objs.begin(), objs.end(), target);
        if (it != objs.end())
        {
            cout << it->getValue() << endl;
            // 20
        }
    }

2 find_if算法

std::find_if 算法是 C++ STL 中用于在一个范围内查找满足特定条件的元素的强大工具。
算法原型:

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

参数:
first, last: 定义要搜索的范围的起始和结束迭代器。
pred: 谓词(predicate)。 谓词是一个函数对象 (函数、函数指针、Lambda 表达式或重载了 operator() 的类),接受一个输入序列的元素作为参数,并返回一个 bool 值。
std::find_if 会查找范围内第一个使 pred 返回 true 的元素,即返回找到的第一个元素的位置。
作用:std::find_if 算法在 [first, last) 范围内查找第一个使谓词 pred 返回 true 的元素。
返回值:
如果找到使 pred 返回 true 的元素,则返回指向该元素的迭代器。
如果范围内没有元素使 pred 返回 true,则返回 last 迭代器。
因此,可以通过比较返回值和 last 来判断是否找到了满足条件的元素。
示例:查找序列中第一个奇数

    void test3()
    {
        std::vector<int> numbers = { 10, 21, 30, 41, 50, 61 };

        // 查找第一个偶数
        auto it = std::find_if(numbers.begin(), numbers.end(), 				[](int x) {
                return x % 2 == 0;
            });
        if (it != numbers.end())
        {
            cout << "find number " << *it << endl;
            // 10 
        }
        else
        {
            cout << "No number" << endl;
        }

        // 返回等于30的元素
        auto it2 = std::find_if(numbers.begin(), numbers.end(), [](int x)->bool{
            return x == 30;
            });

        if (it2 != numbers.end())
        {
            cout << "find number " << *it2 << endl;
            // 30 
        }
        else
        {
            cout << "No number" << endl;
        }
    }

示例2:查找序列,使用函数对象,即自定义类中使用了Operator()。

class IsOdd
 {
 public:
     bool operator()(int x) const
     {
         return x % 2 == 1;
     }
 };
 // 除了 Lambda 表达式,还可以使用函数对象(也称为 functor)作为谓词。
 void test4()
 {
     std::vector<int> numbers = { 10, 21, 30, 41, 50, 61 };
     IsOdd odd;
     // 查找第一个奇数
     auto it = std::find_if(numbers.begin(), numbers.end(), odd);
     if (it != numbers.end())
     {
         cout << "find number " << *it << endl;
         // 10 
     }
     else
     {
         cout << "No number" << endl;
     }
 }

find_if 使用条件:
当需要查找满足特点条件第一个元素时,
当搜索条件不能简单表示为与某个值相等特性比较时:
当需要根据元素的属性或状态进行搜索时:

3 adjacent_find算法

std::adjacent_find 算法是 C++ STL 中用于在一个范围内查找“第一对”相邻的“相等或满足特定关系”的元素的算法。它对于检测序列中的重复项或者符合特定模式的相邻元素非常有用。位于 头文件中。
std::adjacent_find 算法有两个函数原型:
版本 1:查找相邻的相等元素

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

参数:
first, last: 定义要搜索的范围的起始和结束迭代器。
搜索范围是 [first, last),即包含 first 指向的元素,但不包含 last 指向的元素。
此版本使用 == 运算符来比较相邻元素。作用,在 [first, last) 范围内查找第一对相邻的相等元素,即 *i == *(i+1) 的第一对 i。
版本 2:查找满足谓词关系的相邻元素

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

first, last: 定义要搜索的范围的起始和结束迭代器。
pred: 二元谓词(binary predicate)。 这是一个函数对象 (函数、函数指针、Lambda 表达式或重载了 operator() 的类),它接受两个输入序列的元素作为参数,并返回一个 bool 值。 std::adjacent_find 会查找范围内第一对相邻元素,使得 pred(element1, element2) 返回 true。
hanshu作用: 在 [first, last) 范围内查找第一对相邻元素,使得谓词 pred(*i, *(i+1)) 返回 true 的第一对 i。
使用场景:
1 检查序列中的重复项;
2 查找特定的相邻元素,比如前后元素相差2
3 查找序列中的错误,比如本来一个有规律的序列,但是里边有无规律的元素,找出这个元素
实例1:查找相邻的相等元素

    void test5()
    {
		vector<int> numbers = { 1, 2, 2, 3, 4, 5 };
        // 查找第一对相等的相邻元素
		auto it = std::adjacent_find(numbers.begin(), numbers.end());
        if (it != numbers.end())
        {
			cout << "找到相邻的相等元素: " << *it << " " << *(it + 1) << endl;
            // 输出: 找到相邻的相等元素: 2 2
        }
        else
		{
			cout << "未找到相邻的相等元素" << endl;
        }

        // 没有重复的元素
        vector<int> numbers2 = { 1, 2, 3, 4, 5 };
        auto it2 = adjacent_find(numbers2.begin(), numbers2.end());
        if (it2 != numbers2.end())
        {
            cout << "找到相邻的相等元素: " << *it2 << " " << *(it2 + 1) << endl;
            // 输出: 未找到相邻的相等元素
        }
        else
        {
			cout << "未找到相邻的相等元素" << endl;
        }
    }

实例2:查找满足特定关系的相邻元素

  void test6()
  {
      std::vector<int> numbers = { 10, 13, 15, 20, 23, 25, 30 };
      auto it = std::adjacent_find(numbers.begin(), numbers.end(), [](int a, int b) {
          return b - a == 2;
          });
      if (it != numbers.end())
      {
          cout << "元素找到" << *it << "  " << *(it + 1) << endl;
          // 元素找到13  15
      }
      else
      {
          cout << "找不到该元素" << endl;
      }
  }

实例3:找第一对相邻元素,这个序列递减顺序,找到第一个元素比第二个元素大

    void test7()
    {
        std::vector<int> numbers = { 5, 3, 2, 1, 0 };
        auto it = std::adjacent_find(numbers.begin(), numbers.end(), [](int a, int b) {
            return a > b;
            });
        if (it != numbers.end())
        {
            cout << "元素找到" << *it << "  " << *(it + 1) << endl;
            // 元素找到13  15
        }
        else
        {
            cout << "找不到该元素" << endl;
        }
    }

4 binary_search 查找算法

std::binary_search 算法是 C++ STL 中用于在已排序的范围内高效地查找特定元素是否存在的算法。
它利用二分查找的思想,大幅减少了搜索的时间复杂度。
std::binary_search 算法有两个函数原型:
版本 1:使用 < 运算符进行比较

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

参数说明:
first, last: 定义要搜索的范围的起始和结束迭代器。搜索范围是 [first, last),即包含 first 指向的元素,但不包含 last 指向的元素。 这个范围必须是已排序的。
val: 要查找的值。
此版本使用 < 运算符来比较元素,即,范围中的元素类型必须支持 < 运算符,并且必须以升序排序。
返回值:
如果找到值为 val 的元素,则返回 true。
如果没有找到值为 val 的元素,则返回 false。
版本 2:使用自定义比较函数对象

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

参数说明:
first, last: 定义要搜索的范围的起始和结束迭代器。
val: 要查找的值。
comp: 比较函数对象(函数、函数指针、Lambda 表达式或重载了 operator() 的类)。
它接受两个输入序列的元素作为参数,并返回一个 bool 值。 comp(a, b) 应该返回 true 如果 a 小于 b。
范围中的元素必须按照 comp 定义的顺序排序。
返回值:
如果找到值为 val 的元素,则返回 true。
如果没有找到值为 val 的元素,则返回 false。

前提条件:
如果数组未排序,则结果是不可预测的,并且算法可能会返回错误的结果。
使用 std::sort 或其他排序算法来确保范围已排序。
元素类型可比较: 对于版本 1,元素类型必须支持 < 运算符。 对于版本 2,必须提供一个正确的比较函数对象 comp。
实例1:使用默认的 < 运算符

   void test8()
    {
        vector<int>  number = { 1,2,3,4,5 };
        bool found = binary_search(number.begin(), number.end(),3);
        if (found)
        {
            cout << "存在" << endl;
        }
        else
        {
            cout << "不存在" << endl;
        }

    }

实例2:使用自定义比较函数对象

    void test9()
    {
        vector<int>  number = { 5,4,3,2,1 };
        bool found = binary_search(number.begin(), number.end(), 3,
            [](int a, int b) {return a > b; }); // 自定义时是降序的,用 > 
        if (found)
        {
            cout << "存在" << endl;
        }
        else
        {
            cout << "不存在" << endl;
        }
    }

binary_search 总结:
1 这个算法只能确定这个序列中是否存在这个元素,不能输出元素的下标;
2 实现原理是二分查找,时间复杂度O(logn);

5 count算法

std::count 用于统计容器中指定值出现次数,需要对容器中的元素进行计数时很有用。
源码:

    template<class InputIterator, class T>
    typename iterator_traits<InputIterator>::difference_type
    count(InputIterator first, InputIterator last, const T& value);

参数说明
first: 输入范围的起始迭代器。
last: 输入范围的结束迭代器(不包含)。
value: 要统计的目标值。
返回值:
返回目标值 value 在范围 [first, last) 内出现的次数
std::count 的时间复杂度为 O(n),其中 n 是 [first, last) 范围内的元素个数。
它会对范围内的每个元素进行逐一比较。
使用说明:
count可以在任何迭代器上使用,比如 vector,string, deque,list上使用,value类型要与容器中的元素类型相同。
实例1:统计序列中出现3的次数

    void test10()
    {
        std::vector<int> nums = { 1, 2, 3, 4, 2, 2, 5 };
        int target = 2;
        // 使用 std::count 统计 2 出现的次数
        int count = std::count(nums.begin(), nums.end(), target);

        std::cout << "Number " << target << " appears " << count << " times." << std::endl;
        // Number 2 appears 3 times.
    }

示例 2:统计字符串中某个字符的出现次数。

    void test11()
    {
        string str = "Hello World";
        char target = 'l';

        // 统计 l 出现的次数
        int count = std::count(str.begin(), str.end(), target);

        cout << "target 出现次数为:" << target << endl;
        // target 出现次数为:l
    }

6 count_if算法

count_if 用于统计符合特定条件的的元素数量的算法。
相比于 std::count,它更加灵活,因为允许通过自定义谓词函数来定义计数条件。
源码如下:

        template<class InputIterator, class UnaryPredicate>
        typename iterator_traits<InputIterator>::difference_type
        count_if(InputIterator first, InputIterator last, UnaryPredicate pred);

函数作用:
对[first,last)之间的每个元素调用一次 pred。
参数说明:
first: 容器起始迭代器;
last:结束迭代器;
pred: 一元谓词函数,用于指定计数条件,返回true的元素将被计数。
返回值:
[first,last),满足pred条件的元素个数
时间复杂度:逐个遍历,O(n),其中n是[first,last)之间元素个数。
使用说明:
谓词必须返回bool类型,pre必须是一个一元函数或Lambda表达式,接收一个元素并返回true,或 false;
实例1:统计vector中大于5的元素数量

    void test12()
    {
        std::vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        // 使用 std::count_if 统计大于 5 的元素个数
        int count = std::count_if(nums.begin(), nums.end(), [](int x) {
            return x > 5;
        });
        cout << "数量为:" << count << endl;
    }

示例2:统计字符串中元音字母的个数。

    void test13()
    {
        string str = "hello world";

        int count = std::count_if(str.begin(), str.end(), [](char c ) {
                c = std::tolower(c); // 转为小写以便比较
                return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
            });

        cout << "元音字母的数量为:" << count << endl;
        // 元音字母的数量为:3
    }

实例3:统计容器中偶数的数量

    void test14()
    {
        std::vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 
        
        int count = std::count_if(nums.begin(), nums.end(), [](int x) {

            return x % 2 == 0;
            });

        cout << "偶数的数量为:" << count << endl;
    }

8.6.3.4 常用排序算法
1 merge算法

std::merge算法用于合并两个已排序的序列到一个新的已排序序列中。
它不改变原序列的顺序,而是创建一个包含两个输入序列元素的新序列。
函数原型1:

template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator merge (InputIterator1 first1, InputIterator1 last1,
                       InputIterator2 first2, InputIterator2 last2,
                       OutputIterator result);

函数原型2:

template <class InputIterator1, class InputIterator2, class OutputIterator, class Compare>
 OutputIterator merge (InputIterator1 first1, InputIterator1 last1,InputIterator2 first2, InputIterator2 last2,
 OutputIterator result, Compare comp);

参数:
first1, last1: 定义第一个已排序输入序列的范围,即 [first1, last1)。
first2, last2: 定义第二个已排序输入序列的范围,即 [first2, last2)。
result: 指向目标序列起始位置的迭代器。
result 必须指向一个足够大的空间,以便容纳两个输入序列的所有元素。
comp (可选): 一个二元谓词(函数对象或函数指针),用于比较两个元素。如果省略,则默认使用 operator< 进行比较。
返回值:
返回一个迭代器,指向合并后的序列的末尾,也就是result加上合并的元素的数量。
要求:
[first1, last1) 和 [first2, last2) 都必须是已排序的序列。
排序标准要么是默认的 operator<,要么是由提供的 comp 函数对象决定的。
result 指向的目标序列必须有足够的空间来容纳所有元素。
InputIterator1, InputIterator2, OutputIterator 都是满足输入迭代器和输出迭代器要求的迭代器类型。
工作原理:
merge 算法通过比较两个输入序列的元素,并将较小的(或者根据 comp 更“小”的)元素复制到 result 指向的序列中。它迭代两个输入序列,直到其中一个序列到达末尾。然后,它将另一个序列中剩余的元素全部复制到 result 指向的序列中。
时间复杂度: O(n+m),其中 n 和 m 分别是两个输入序列的长度。
空间复杂度: 如果 result 指向的序列是在原地时O(1) ,当 result 指向一个新的内存区域时是 O(n+m) 。
实例1:合并升序的序列

    void test1()
    {
        std::vector<int> v1 = { 1, 3, 5, 7, 9 };
        std::vector<int> v2 = { 2, 4, 6, 8, 10 };
        std::vector<int> result(v1.size() + v2.size()); // 必须分配足够的空间
        std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());
        for_each(result.begin(), result.end(), [](int value) {
            cout << value << "  ";
        }); 
        cout << endl;
        // 1  2  3  4  5  6  7  8  9  10

    }

示例2:合并降序的序列

    void test2()
    {
        std::vector<int> v1 = {6,4,2,1 };
        std::vector<int> v2 = { 77,44,22,1 };
        std::vector<int> result(v1.size() + v2.size()); // 必须分配足够的空间
        std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin(),greater<int>());
        for_each(result.begin(), result.end(), [](int value) {
            cout << value << "  ";
        });
        cout << endl;
        // 77  44  22  6  4  2  1  1
    }

示例3:合并自身
    void test3()
    {
        std::vector<int> v5 = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
        std::sort(v5.begin(), v5.begin() + 5);
        std::sort(v5.begin() + 5, v5.end());

        // 临时缓冲区
        vector<int> tmp(v5.size());

        // 合并
        std::merge(v5.begin(), v5.begin() + 5, v5.begin() + 5, v5.end(), tmp.begin());
        v5.swap(tmp);

        for_each(v5.begin(), v5.end(), [](int value) {
            cout << value << "  ";
            });
        cout << endl;
        // 1  2  3  4  5  6  7  8  9  10
    }

何时使用merge???
当需要将两个或多个已排序的序列合并到一个新的已排序序列时。
当需要保持原始序列不变时。
std::merge 和 std::inplace_merge 的区别:
std::merge 将结果写入一个新的序列,而 std::inplace_merge原地合并一个序列的两个已排序的子序列(例如,[first, middle) 和 [middle, last))。
std::inplace_merge 通常需要一个辅助缓冲区,其大小等于两个子序列长度之和,以便高效地进行原地合并。

2 sort 算法

std::sort 是 C++ 标准模板库 (STL) 中最常用的排序算法之一。
它提供了高效且通用的排序功能,可以对各种容器中的元素进行排序。

    template <class RandomAccessIterator>
    void sort(RandomAccessIterator first, RandomAccessIterator last);
    template <class RandomAccessIterator, class Compare>
    void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

参数:
first, last: 定义要排序的序列范围,即 [first, last)。
first 指向序列的起始位置,last 指向序列的末尾位置(不包含在序列中)。
comp (可选): 一个二元谓词(函数对象或函数指针),用于比较两个元素。如果省略,则默认使用 operator< 进行比较,即升序排序。
std::sort 函数没有返回值(void)。
它直接修改输入序列的内容,将其排序。
工作原理:std::sort 的底层实现通常是 IntroSort,一种混合排序算法,它结合了快速排序、堆排序和插入排序的优点,以提供最佳的平均性能和避免最坏情况下的性能退化。
快速排序: 作为主要算法,它通过选择一个枢轴 (pivot) 元素,将序列划分为两个子序列:
一个子序列的元素小于枢轴,另一个子序列的元素大于枢轴。 然后递归地对这两个子序列进行排序。
快速排序的平均时间复杂度是 O(n log n),但最坏情况下的时间复杂度是 O(n^2)。
堆排序: 用于避免快速排序在某些情况下的 O(n^2) 最坏情况。
当快速排序递归深度超过一定限制时,std::sort 切换到堆排序。
堆排序的时间复杂度始终是 O(n log n)。
插入排序: 用于处理小规模的子序列。当子序列的大小变得足够小时,std::sort 切换到插入排序,因为它在小规模序列上的性能优于快速排序和堆排序。
示例:

void test4()
 {
     // 1 使用默认的升序排序
     std::vector<int> v = { 5, 2, 8, 1, 9, 4 };
     std::sort(v.begin(), v.end());
     for_each(v.begin(), v.end(), [](int value) {
         cout << value << "  ";
     });
     cout << endl;
     // 1  2  4  5  8  9

     // 2 降序排序
     vector<int> v2 = { 4,3,5,6,3,1 };
     std::sort(v2.begin(), v2.end(), greater<int>());
     for_each(v2.begin(), v2.end(), [](int value) {
         cout << value << "  ";
         });
     cout << endl;
     // 6  5  4  3  3  1

     // 3 排序自定义对象
     struct Person {
         std::string name;
         int age;
     };
     vector<Person> people = {
        {"anna",1},
        {"anna",3},
        {"anna",2},
     };

     // 对年龄排序
     sort(people.begin(), people.end(), [](const Person& a, const Person& b) {
         return a.age < b.age;
     });
     for_each(people.begin(), people.end(), [](const Person& a) {
         cout << a.name << "  " << a.age << endl;;
         });
     cout << endl;
     /*
         anna  1
         anna  2
         anna  3
     */
 }

sort() 注意事项
std::sort 只能用于提供随机访问迭代器的容器。
如果需要对 std::list 或 std::forward_list 进行排序,应该使用其成员函数 sort()。
std::sort 不保证排序的稳定性。即,如果两个元素相等(根据比较函数),它们的相对顺序在排序后可能发生变化。
如果需要稳定排序,可以使用 std::stable_sort。
对空范围 [first, last) 调用 std::sort 是安全的,它不会执行任何操作。
如果只需要排序序列中的一部分元素,可以使用 std::partial_sort。
sort使用场景:
当需要对容器中的元素进行排序,并且容器提供随机访问迭代器时。
当不需要保证排序的稳定性时。
当需要一个高效的通用排序算法时。
当需要对整个序列进行排序时。
std::sort 和 std::stable_sort 的区别:
std::sort 不保证排序的稳定性,而 std::stable_sort 保证稳定性。即,如果两个元素相等,它们的相对顺序在排序后不会改变。
std::stable_sort 通常比 std::sort 慢,特别是对于大规模的序列。
std::stable_sort 可能需要额外的内存空间。
std::sort 和 std::partial_sort 的区别:
std::sort 对整个序列进行排序,而 std::partial_sort 只对序列中的一部分元素进行排序。
std::partial_sort 可以用来找到序列中最小或最大的 k 个元素。记住这句话,会考哦~

3 shuffle算法

std::shuffle (推荐使用)函数原型:

    template <class RandomAccessIterator, class URBG>
    void shuffle (RandomAccessIterator first, RandomAccessIterator last, URBG&& g);

参数:
first, last: 定义要打乱的序列范围,即 [first, last)。
g: 一个 均匀随机数生成器 (简称 URBG)。 这是一个可调用对象,可以生成均匀分布的随机数。
std::mt19937 和 std::minstd_rand 等都是 URBG 的例子。
std::shuffle 函数也没有返回值(void)。 它直接修改输入序列的内容,将其随机打乱。
工作原理:std::shuffle 算法也使用 Fisher-Yates 洗牌算法。
它与 std::random_shuffle 的主要区别在于它使用用户提供的 URBG 来生成随机数,而不是依赖于 std::rand。

    void test5()
    {
        vector<int> v = { 1,2,3,4,5 };

        std::random_device rd; // 用于位随机数引擎提供种子
        std::mt19937 gen(rd()); // // 梅森旋转算法,高质量的随机数生成器
        std::shuffle(v.begin(), v.end(), gen);
        for_each(v.begin(), v.end(), [](int v) {
            cout << v << "  ";
            });
        cout << endl;
        // 2  4  1  5  3
        // 3  5  2  1  4
        // 5  1  4  2  3
    }

创建一个高质量的随机数生成器对象(URBG),例如 std::mt19937。
使用 std::random_device 为生成器提供种子,可以获得更好的随机性。

    void test()
    {
        // 创建随机设备和生成器
        std::random_device rd;    // 硬件随机数生成器,用于获取种子
        std::mt19937 gen(rd());   // 梅森旋转算法随机数生成器

        // 创建均匀分布器,生成1-100之间的整数
        std::uniform_int_distribution<int> dis(1, 100);
        cout << "生成10个1-100之间的随机数:" << endl;
        for (int i = 0; i < 10; ++i)
        {
            int randomNum = dis(gen);
            cout << randomNum << " ";
        }
        cout << endl;
        /*
        生成10个1-100之间的随机数:
        61 10 18 29 4 63 61 23 37 64
        */
    }

4 reverse()

std::reverse 算法用于反转指定范围内的元素顺序。即,序列中的第一个元素将变为最后一个元素,第二个元素将变为倒数第二个元素,依此类推。
函数原型:

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

工作原理:std::reverse 算法通过交换序列中第一个元素和最后一个元素、第二个元素和倒数第二个元素,依此类推,
直到达到序列的中间位置,从而实现反转。
时间复杂度: O(n) 。
空间复杂度: O(1), std::reverse 是一种原地算法,只需要常量级的额外空间。

void test6()
 {
     // 反转 vector 
     std::vector<int> v = { 1, 2, 3, 4, 5 };
     std::reverse(v.begin(), v.end());
     for_each(v.begin(), v.end(), [](int v) {
         cout << v << "  ";
         });
     cout << endl;
     // 5 4 3 2 1 

     // 2 反转 array
     array<int,5> arr = {1, 2, 3, 4, 5};
     std::reverse(arr.begin(), arr.end());
     for_each(arr.begin(), arr.end(), [](int v) {
         cout << v << "  ";
         });
     cout << endl;
     // 5 4 3 2 1 

     // 3 反转list
     std::list<int> lst = { 100, 200, 300, 400, 500 };
     std::reverse(lst.begin(), lst.end());
     for_each(lst.begin(), lst.end(), [](int v) {
         cout << v << "  ";
         });
     cout << endl;
     // 500  400  300  200  100

     // 4 反转字符串
     std::string str = "hello";
     std::reverse(str.begin(), str.end());
     cout << str << endl;
     // olleh
 }

使用场景:
当需要反转容器中的元素顺序时。
当需要反转字符串时。
当需要原地反转序列,而不需要创建副本时。
容器提供了双向迭代器。

8.6.3.5 拷贝替换算法
1 copy算法

copy 用于将元素从一个范围复制到另一个范围.该算法提供了高效且通用的方式来实现复制操作,并且可以与各种迭代器和数据类型配合使用。
原型:

template <class InputIterator, class OutputIterator>
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result);

template <class InputIterator, class OutputIterator>
OutputIterator copy_n (InputIterator first, size_t n, OutputIterator result); // 从 C++11 起

参数:
 first: 指向输入范围开始的输入迭代器。
 last: 指向输入范围结束的输入迭代器。 注意:[first, last) 范围是左闭右开区间,last 指向 不 包含在范围中的元素。
 result: 指向输出范围开始的输出迭代器。
 n: (copy_n 特有) 要复制的元素数量。
copy不会为输出范围分配内存。在使用 copy 之前,必须确保输出范围有足够的空间容纳要复制的元素。
否则,会导致未定义行为,例如内存覆盖。当源范围和目标范围重叠时,行为是未定义的,除非 result 在 [first, last) 之外。如果需要处理重叠范围,使用 std::move 或 std::copy_backward。

   void test()
   {
       // 1 从vector 复制到 vector
       vector<int> source = { 1,2,3,4,5 };
       vector<int> destination(source.size(), 0);

       std::copy(source.begin(), source.begin() + 4, destination.begin() + 1);
       std::for_each(destination.begin(), destination.end(), [](int value)
           {
               cout <<   value << "    ";
           });
       cout << endl;
       // 0    1    2    3    4

       // 2 从array到vector
       int arr[] = { 1,2,3,4,5 };
       std::vector<int> dest2(sizeof(arr) / sizeof(arr[0]));
       std::copy(std::begin(arr), std::end(arr), dest2.begin());
       std::for_each(dest2.begin(), dest2.end(), [](int value)
           {
               cout << value << "    ";
           });
       cout << endl;
       // 1    2    3    4    5

       // 3 从 vector 到 array
       vector<int> source_vector = { 1,2,3,4,5 };
       int dest_array[5];
       std::copy(source_vector.begin(), source_vector.end(), begin(dest_array));
       std::for_each(begin(dest_array), end(dest_array), [](int value)
           {
               cout << value << "    ";
           });
       cout << endl;
       // 1    2    3    4    5

       // 4 copy_n 的使用
       std::vector<int> source_n = { 1,2,3,4,5 };
       std::vector<int> dest_n(4); // 保存前4个
       std::copy_n(source_n.begin(), 4, dest_n.begin());
       std::for_each(begin(dest_n), end(dest_n), [](int value)
           {
               cout << value << "    ";
           });
       cout << endl;
       // 1    2    3    4

       // 5 复制到 ostream (例如 cout)
       std::vector<int> data = { 1,2,3,4,5 };
       cout << "data = " << endl;
       std::copy(data.begin(), data.end(), std::ostream_iterator<int>(std::cout, "  ")); 
       cout << endl;
       // 1  2  3  4  5
       // std::ostream_iterator 是一个输出迭代器,可以将元素写入 std::ostream 对象,第一个参数输出流,可以写入到文件,可以输出的控制台
       // 参见:8.5.2 迭代器分类,输出迭代器,
       // 6 复制字符串
       std::string src = "hello";
       std::string dest_s(src.size(), ' ');
       std::copy(src.begin(), src.end(), dest_s.begin());
       cout << "dest_s = " << dest_s << endl;
       // dest_s = hello
        
   }

复制相关算法:
std::move: 将元素 移动 而不是复制到新的位置。 这对于移动语义很重要,尤其是对于大型对象,可以避免不必要的复制开销。
std::copy_if ,c++11引入,根据特定条件复制元素
std::copy_backward: 从输入范围的末尾开始复制元素到输出范围,这对于处理重叠范围非常有用,尤其是在输出范围位于输入范围的前面时。
std::generate: 用一个函数生成的值填充输出范围。
何时使用 std::copy:
当需要将一个容器或数组中的元素复制到另一个容器或数组时。
当需要将数据输出到流(例如 std::cout)时。
当需要创建一个容器或数组的副本时。
当需要将数据传递给需要指定迭代器范围的函数时。

2 replace算法

std::replace用于将特定范围内的所有等于特定值的元素替换为另一个值。
原型:

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

 template <class ExecutionPolicy, class ForwardIterator, class T>
 void replace (ExecutionPolicy policy, ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value); // C++17 并行版本

参数:
 first: 指向要操作范围的开始的迭代器。
 last: 指向要操作范围的结束的迭代器(不包含在范围内)。 范围是 [first, last)。
 old_value: 要被替换的值。
 new_value: 用于替换 old_value 的新值。
 policy: (C++17 并行版本) 指定执行策略,例如 std::execution::par 用于并行执行。
替换方式:
replace 算法遍历 [first, last) 范围内的每个元素,使用 == 运算符来比较元素与 old_value,如果元素的值等于 old_value,则将其替换为 new_value。

    void test1()
    {
        // 1 替换vector 中的元素
        vector<int> numbers = { 1,2,3,4,5,6 };
        std::replace(numbers.begin(), numbers.end(), 2, 10);
        std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<int>(std::cout, " "));
        cout << endl;
        // 1 10 3 4 5 6

        // 2 替换 C数组中的元素
        int arr[] = { 1,2,3,4,5 };
        std::replace(std::begin(arr), std::end(arr), 2, 11);
        std::for_each(std::begin(arr), std::end(arr), [](int value) {
            cout << value << "  ";
            });
        cout << endl;
        // 1  11  3  4  5

        // 3 替换字符串中的字符
        // 将字符串中的 'l' 替换为 'h'
        string text = "hello";
        std::replace(text.begin(), text.end(), 'l', 'j');
        cout << text << endl;
        cout << endl;
        // hejjo

#ifdef __cpp_parallelism // 检测编译器是否支持并行执行
        std::vector<int> large_data(1000000, 0);
        for (int i = 0; i < 1000000; ++i)
        {
            if (i % 100 == 0) large_data[i] = 42;
        }


        std::replace(std::execution::par, large_data.begin(), large_data.end(), 42, 99);

        // 验证一小部分元素,看是否替换成功
        for (int i = 0; i < 1000; ++i)
        {
            if (i % 100 == 0)
            {
                cout << large_data[i] << "  ";
            }
        }
        cout << endl;
#endif
    }

replace_if 用法
如果需要替换更复杂的条件,而不简单的相等比较,使用std::replace_if算法。
std::replace_if 接受一个谓词(一个返回布尔值的函数或函数对象)作为参数,并仅替换谓词返回 true 的元素。


void test2()
 {
     std::vector<int> numbers = { 1, 2, 3, 4, 5, 6 };

     // 1 将偶数替换为0
     std::replace_if(numbers.begin(), numbers.end(), [](int n) {
                
             return n % 2 == 0;
            
         }, 0);
     std::for_each(std::begin(numbers), std::end(numbers), [](int value) {
         cout << value << "  ";
         });
     // 1  0  3  0  5  0  
     cout << endl;
     // 2 将小于5个元素替换为100
     std::replace_if(numbers.begin(), numbers.end(), [](int n) {

         return n < 5;

         }, 100);
     std::for_each(std::begin(numbers), std::end(numbers), [](int value) {
         cout << value << "  ";
         });
     cout << endl;
     // 100  100  100  100  5  100
 }

何时使用 replace呢?

  • 当需要将容器或数组中所有出现的特定值替换为另一个值时:
  • 当需要修改字符串中的特定字符时;
  • 当需要清理或标准化数据时;
  • 当需要实现特定的转换和映射时
3 swap算法

作用:std::swap 用于交换两个变量或对象的值。它是一个基本的工具,被广泛用于各种算法和数据结构中。
原型:

        template <class T>
        void swap (T& a, T& b);

        template <class T>
        constexpr void iter_swap (T a, T b); //需要是迭代器类型

swap 使用引用传递 (T&) 作为参数,这意味着它直接操作传递给它的原始变量/对象,而不是创建副本。从 C++11 开始,swap 和 iter_swap 可以声明为 constexpr,可以在编译时执行,前提是参数也是编译时常量。


void test3()
 {
     // 1. 交换 int 变量
     int x = 10;
     int y = 211;
     std::cout << "Before swap: x = " << x << ", y = " << y << std::endl; 
     // Before swap: x = 10, y = 211
     std::swap(x, y);
     std::cout << "After swap: x = " << x << ", y = " << y << std::endl; 
     // After swap: x = 211, y = 10

     // 2 交换 string 对象
     string str1 = "hello";
     string str2 = "world";
     std::cout << "Before swap: str1 = " << str1 << ", str2 = " << str2 << std::endl;
     // Before swap: str1 = hello, str2 = world
     swap(str1, str2);
     std::cout << "After swap: str1 = " << str1 << ", str2 = " << str2 << std::endl;
     // After swap: str1 = world, str2 = hello

     // 3 交换 vector 中的元素 (使用 iter_swap)
     std::vector<int> vec = { 1,2,3,4,5 };
     std::for_each(vec.begin(), vec.end(), [](int value) {
         cout << value << "  ";
         });
     cout << endl;
     // 1  2  3  4  5
     std::iter_swap(vec.begin(), vec.begin() + 2);
     std::for_each(vec.begin(), vec.end(), [](int value) {
         cout << value << "  ";
         });
     // 3  2  1  4  5
     cout << endl;

     // 4 交换两个容器:复杂度是 O(1)
     vector<int> vec1{ 1,2,3,4 };
     vector<int> vec2{ 5,6,7,8 };
     std::swap(vec1, vec2);
     // 输出vec1 
     std::for_each(vec1.begin(), vec1.end(), [](int value) {
         cout << value << "  ";
         });
     cout << endl;
     // 5  6  7  8
     std::for_each(vec2.begin(), vec2.end(), [](int value) {
         cout << value << "  ";
         });
     cout << endl;
     // 1  2  3  4
 }

当需要在算法中交换两个元素的位置时(例如,排序算法)。

  • 当需要交换容器中的两个元素时。
  • 当需要交换两个对象的状态时。
  • 当需要自定义数据结构的 swap 操作时。
8.6.3.6 算术生成算法
1 算术生成算法std::accumulate

std::accumulate 是 C++ 标准库 头文件中的一个算法,用于计算一个范围内所有元素的累积结果,即执行某种累加操作。可以用于求和、求积、连接字符串等多种操作。std::accumulate 有两个重载版本。
版本 1:默认加法

template <class InputIterator, class T>
T accumulate (InputIterator first, InputIterator last, T init);

版本 2:自定义操作

template <class InputIterator, class T, class BinaryOperation>
T accumulate (InputIterator first, InputIterator last, T init, BinaryOperation op);

op参数是 一个二元操作符(可以是函数对象、函数指针或 lambda 表达式),接受两个参数,一个是当前累积的结果,另一个是当前迭代器指向的元素。它返回一个新的累积结果。
init 是累积的初始值。它的类型决定了最终结果的类型。选择合适的初始值非常重要
例如,如果计算乘积,初始值应该是 1 而不是 0。
对于字符串连接,初始值应该是一个空字符串。
假设有 std::accumulate(first, last, init, op),算法的基本流程是:

        // 1.
        result = init;
        // 2.
        for (auto it = first; it != last; ++it);
        result = op(result, *it);
        // 3.
        return result;

// 示例1:求和,自动操作
 void test2()
 {
     // 求和,
     std::vector<int> numbers = { 1, 2, 3, 4, 5 };
     int sum = std::accumulate(numbers.begin(), numbers.end(), 0);
     std::cout << "Sum: " << sum << std::endl;
     // Sum: 15
 }
 // 示例2:求和 自定义Lambda表达式
 void test1()
 {
     std::vector<int>  numbers = { 1, 2, 3, 4, 5 };
     int sum = std::accumulate(numbers.begin(), numbers.end(), 0, [](int acc, int val) {
         return acc + val;
         });
     std::cout << "Sum: " << sum << std::endl;
     // Sum: 15
 }

 // 示例 3: 求积 (自定义操作 - lambda表达式)
 void test3()
 {
     std::vector<int>  numbers = { 1, 2, 3, 4, 5 };
     int product = std::accumulate(numbers.begin(), numbers.end(), 1, [](int acc, int val) {
         return acc * val;
     });
     std::cout << "Sum: " << product << std::endl;
     // Sum: 120
 }
 ///示例 4: 字符串连接(自定义操作 - lambda表达式)
 void test4()
 {
     std::vector<std::string> words = { "Hello", ", ", "World", "!" };
     string str = std::accumulate(words.begin(), words.end(), std::string(""), [](string& acc, string& word) {

         return acc + word;
         });
     cout << str << endl;
     // Hello, World!
 }

 // 示例5:使用函数对象
 struct StringConcatenator
 {
     std::string operator()(const std::string& acc, const std::string& word) const 
     {
         return acc + word;
     }
 };
 void test()
 {
     std::vector<std::string> words = { "Hello", ", ", "World", "!" };
     string str = std::accumulate(words.begin(), words.end(), std::string(""), StringConcatenator());
     cout << str << endl;
     // Hello, World!
 }

算法复杂度:std::accumulate 的时间复杂度为 O(N),其中 N 是输入范围中元素的数量。可读性和效率:std::accumulate 比手动编写循环进行累积操作更简洁、更易读。
std::accumulate 适用于各种需要对序列中的元素进行累积操作的场景,例如:
 计算数组或向量中所有元素的总和、平均值、乘积。
 连接字符串序列。
 计算自定义的统计量。
 实现复杂的折叠操作。

2 fill 算法

std::fill 是 C++ 标准库 头文件中的一个算法,用于将指定范围内的元素全部设置为给定的值。它是一个非常简单但常用的算法,用于初始化容器或者覆盖容器中的现有数据。
函数原型:

        template <class ForwardIterator, class T>
        void fill (ForwardIterator first, ForwardIterator last, const T& val);
        std::fill 遍历输入范围 [first, last),并将该范围内的每个元素设置为 val 的副本。
        std::fill 的基本流程是:
        for (auto it = first; it != last; ++it) {
            *it = val;
        }

// 示例 1: 使用 std::fill 初始化 std::vector
 void test1()
 {
     std::vector<int> numbers(5); // 创建一个大小为 5 的 vector,未初始化
     std::fill(numbers.begin(), numbers.end(), 10);

     for (int number : numbers) {
         std::cout << number << " ";
     }
     std::cout << std::endl;
     // 10 10 10 10 10
 }

 // 示例2:使用 std::fill 修改 std::array
 void test2()
 {
     std::array<int, 5> numbers = { 1,2,3,4,5 };
     std::fill(numbers.begin() + 1, numbers.end() - 1, 0);
     for (int number : numbers) {
         std::cout << number << " ";
     }
     std::cout << std::endl;
     // 1 0 0 0 5
 }

 // 示例 3: 使用 std::fill 设置指针指向的内存区域
 void test3()
 {
     // 填充 C 方式数组
     int arr[5];
     std::fill(arr, arr + 5, -4);
     for (int number : arr) 
     {
         std::cout << number << " ";
     }
     std::cout << std::endl;
     // -4 -4 -4 -4 -4
 }

 // 示例 4: 使用 std::fill 设置 std::string 的一部分
 void test4()
 {
     string str = "abcdefg";
     std::fill(str.begin(), str.end(), 'X');
     std::cout << str << std::endl;
     // XXXXXXX
     // std::fill 会覆盖范围内的所有现有数据。
     // 如果只想有条件地设置某些元素的值,请考虑使用其他算法,例如 std::replace_if。
     // 效率:std::fill 的时间复杂度为 O(N),其中 N 是输入范围中元素的数量。  对于大型范围,这需要一些时间。
 }

std::fill 适用于以下场景:
初始化容器,将所有元素设置为相同的初始值。
重置容器中的数据。
将数组或字符串的一部分设置为特定的值。
在调试过程中,用特定的值填充内存区域,以检测错误。
std::fill 和 std::fill_n 都是用于填充范围的算法,但它们之间有一些关键的区别:
std::fill: 接受起始迭代器 first 和结束迭代器 last 作为参数,明确指定要填充的范围。
std::fill_n: 接受起始迭代器 first 和要填充的元素数量 n 作为参数。
因此,std::fill 适用于已知范围的情况,而 std::fill_n 适用于已知要填充的元素数量的情况。

    void test()
    {
        std::vector<int> numbers(10);

        // 使用 std::fill 将所有元素设置为 5
        std::fill(numbers.begin(), numbers.end(), 5);

        // 使用 std::fill_n 将前 3 个元素设置为 0
        std::fill_n(numbers.begin(), 3, 0);

        for (int number : numbers) {
            std::cout << number << " "; // Output: 0 0 0 5 5 5 5 5 5 5
        }
        std::cout << std::endl;
        // 0 0 0 5 5 5 5 5 5 5
    }

C++ 标准模板库 (STL) 算法是现代 C++ 开发中不可或缺的基石,它提供了强大、高效且通用的工具集,
能够显著提升代码的质量和开发效率。
STL 算法的多个核心类别及其常用函数,包括:
遍历算法:如 for_each 和 transform,它们允许我们对容器中的每个元素执行指定的操作,无论是简单的打印还是复杂的转换。
查找算法:如 find、find_if、adjacent_find、binary_search、count 和 count_if。
排序算法:如 merge、sort、shuffle 和 reverse。 sort 提供了高效的通用排序功能,而 merge 则用于合并两个已排序的序列。
拷贝替换算法:如 copy、replace 和 swap。
算术生成算法:如 accumulate 和 fill。
STL 算法经过高度优化,在性能上往往优于手写实现,并且能够提高代码的可读性、可维护性和通用性。

8.6.3.7 生成等差数列

生成一个等差数列。

		std::vector<int> sequence(n);
			// 从1开始生成等差数列,公差为1
			std::iota(sequence.begin(), sequence.end(), 1);

方式2:使用generate

std::vector<int> sequence(n);

int current = 1;  // 起始值
std::generate(sequence.begin(), sequence.end(), [&current]() {
    return current++;
});
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐