C++_chapter8_STL算法
本文记录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(), [¤t]() {
return current++;
});
更多推荐
所有评论(0)