学到的新知识
std::vector::resize
std::vector::resize
是 C++ 标准库中 std::vector
类的一个成员函数,用于调整向量的大小。它可以增加或减少向量中元素的数量,并根据需要初始化新元素或删除多余的元素。
函数原型
std::vector::resize
有两个重载版本:
-
调整大小并默认初始化新元素:
void resize(size_type n);
n
:新的向量大小。- 如果
n
大于当前大小,向量会扩展,新增的元素会被默认初始化(对于基本类型如int
,初始化为0
;对于类类型,调用默认构造函数)。 - 如果
n
小于当前大小,向量会缩小,多余的元素会被删除。
-
调整大小并使用指定值初始化新元素:
void resize(size_type n, const value_type& val);
n
:新的向量大小。val
:用于初始化新元素的值。- 如果
n
大于当前大小,向量会扩展,新增的元素会被初始化为val
。 - 如果
n
小于当前大小,向量会缩小,多余的元素会被删除。
使用示例
示例 1:调整大小并默认初始化
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3};
// 将向量大小调整为 5,新增的元素默认初始化为 0
vec.resize(5);
for (int i : vec) {
std::cout << i << " "; // 输出: 1 2 3 0 0
}
std::cout << std::endl;
// 将向量大小调整为 2,多余的元素被删除
vec.resize(2);
for (int i : vec) {
std::cout << i << " "; // 输出: 1 2
}
std::cout << std::endl;
return 0;
}
示例 2:调整大小并使用指定值初始化
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3};
// 将向量大小调整为 5,新增的元素初始化为 10
vec.resize(5, 10);
for (int i : vec) {
std::cout << i << " "; // 输出: 1 2 3 10 10
}
std::cout << std::endl;
// 将向量大小调整为 2,多余的元素被删除
vec.resize(2, 10); // 注意:第二个参数在这里没有作用,因为向量是缩小
for (int i : vec) {
std::cout << i << " "; // 输出: 1 2
}
std::cout << std::endl;
return 0;
}
注意事项
-
性能:
- 如果
resize
增加向量的大小,可能会导致内存重新分配(如果当前容量不足)。 - 如果
resize
减少向量的大小,不会释放内存(capacity
不变),只是逻辑上减少元素数量。
- 如果
-
默认初始化:
- 对于基本类型(如
int
、double
等),默认初始化会将值设为0
。 - 对于类类型,默认初始化会调用默认构造函数。
- 对于基本类型(如
-
缩小向量:
- 当
resize
缩小向量时,多余的元素会被销毁(调用析构函数),但向量的容量(capacity
)不会改变。
- 当
-
与
reserve
的区别:reserve
只分配内存,不改变向量的大小(size
)。resize
会改变向量的大小(size
),并根据需要分配内存。
总结
std::vector::resize
是一个非常实用的函数,用于动态调整向量的大小。它可以根据需要扩展或缩小向量,并支持默认初始化或指定值初始化新元素。在实际开发中,合理使用 resize
可以避免手动管理内存的麻烦。
std::accumulate
std::accumulate
是 C++ 标准库 <numeric>
头文件中的一个算法函数,用于计算一个范围内元素的累加值(或自定义的累积操作)。它是处理数值计算时非常常用的工具。
函数原型
std::accumulate
有两个重载版本:
-
基本版本:
template<class InputIt, class T> T accumulate(InputIt first, InputIt last, T init);
first
和last
:定义了一个范围[first, last)
,表示要处理的元素。init
:初始值,累加的结果会从这个值开始。- 返回值:范围内所有元素的累加结果。
-
带自定义操作的版本:
template<class InputIt, class T, class BinaryOperation> T accumulate(InputIt first, InputIt last, T init, BinaryOperation op);
first
和last
:定义了一个范围[first, last)
,表示要处理的元素。init
:初始值。op
:一个二元操作函数(或函数对象),用于定义如何累积元素。- 返回值:范围内所有元素根据
op
操作累积的结果。
基本用法
示例 1:累加整数
#include <iostream>
#include <numeric> // 包含 accumulate
#include <vector>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
// 计算累加和,初始值为 0
int sum = std::accumulate(nums.begin(), nums.end(), 0);
std::cout << "Sum: " << sum << std::endl; // 输出: Sum: 15
return 0;
}
示例 2:累加浮点数
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<double> nums = {1.1, 2.2, 3.3, 4.4, 5.5};
// 计算累加和,初始值为 0.0
double sum = std::accumulate(nums.begin(), nums.end(), 0.0);
std::cout << "Sum: " << sum << std::endl; // 输出: Sum: 16.5
return 0;
}
自定义操作
std::accumulate
的第二个版本允许你自定义累积操作。你可以传递一个二元函数(或 lambda 表达式)来定义如何累积元素。
示例 3:累乘
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
// 计算累乘积,初始值为 1
int product = std::accumulate(nums.begin(), nums.end(), 1, [](int a, int b) {
return a * b;
});
std::cout << "Product: " << product << std::endl; // 输出: Product: 120
return 0;
}
示例 4:连接字符串
#include <iostream>
#include <numeric>
#include <vector>
#include <string>
int main() {
std::vector<std::string> words = {"Hello", " ", "World", "!"};
// 连接字符串,初始值为空字符串
std::string result = std::accumulate(words.begin(), words.end(), std::string(""));
std::cout << "Concatenated: " << result << std::endl; // 输出: Concatenated: Hello World!
return 0;
}
注意事项
-
初始值类型:
- 初始值
init
的类型决定了accumulate
的返回类型。例如,如果init
是int
,则结果也是int
;如果init
是double
,则结果是double
。 - 如果初始值类型与元素类型不匹配,可能会导致意外的类型转换。
- 初始值
-
自定义操作:
- 自定义操作函数
op
必须满足以下条件:- 接受两个参数:第一个是累积值,第二个是当前元素。
- 返回一个新的累积值。
- 自定义操作函数
-
空范围:
- 如果范围
[first, last)
为空,accumulate
会直接返回初始值init
。
- 如果范围
-
性能:
accumulate
的时间复杂度是线性的,即 O(n),其中 n 是范围内元素的数量。
总结
std::accumulate
是一个强大的工具,可以用于计算累加、累乘、字符串连接等操作。它的灵活性在于支持自定义操作,使得它可以适应各种累积计算的需求。在实际开发中,合理使用 accumulate
可以简化代码并提高可读性。
std::max_element
std::max_element
是 C++ 标准库 <algorithm>
头文件中的一个算法函数,用于查找范围内最大元素的迭代器。它可以用于数组、向量、列表等容器,支持自定义比较函数。
函数原型
std::max_element
有两个重载版本:
-
基本版本:
template<class ForwardIt> ForwardIt max_element(ForwardIt first, ForwardIt last);
first
和last
:定义了一个范围[first, last)
,表示要查找的元素。- 返回值:指向范围内最大元素的迭代器。如果范围为空,返回
last
。
-
带自定义比较函数的版本:
template<class ForwardIt, class Compare> ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp);
first
和last
:定义了一个范围[first, last)
,表示要查找的元素。comp
:一个二元比较函数(或函数对象),用于定义如何比较元素。- 返回值:指向范围内最大元素的迭代器。如果范围为空,返回
last
。
基本用法
示例 1:查找最大元素
#include <iostream>
#include <algorithm> // 包含 max_element
#include <vector>
int main() {
std::vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6};
// 查找最大元素的迭代器
auto max_it = std::max_element(nums.begin(), nums.end());
if (max_it != nums.end()) {
std::cout << "Max element: " << *max_it << std::endl; // 输出: Max element: 9
std::cout << "Position: " << std::distance(nums.begin(), max_it) << std::endl; // 输出: Position: 5
}
return 0;
}
示例 2:查找最大元素(数组)
#include <iostream>
#include <algorithm>
int main() {
int arr[] = {3, 1, 4, 1, 5, 9, 2, 6};
int n = sizeof(arr) / sizeof(arr[0]);
// 查找最大元素的指针
int* max_ptr = std::max_element(arr, arr + n);
if (max_ptr != arr + n) {
std::cout << "Max element: " << *max_ptr << std::endl; // 输出: Max element: 9
std::cout << "Position: " << std::distance(arr, max_ptr) << std::endl; // 输出: Position: 5
}
return 0;
}
自定义比较函数
std::max_element
的第二个版本允许你自定义比较函数,用于定义什么是“最大”。
示例 3:查找最长字符串
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
int main() {
std::vector<std::string> words = {"apple", "banana", "cherry", "date"};
// 查找最长的字符串
auto max_it = std::max_element(words.begin(), words.end(), [](const std::string& a, const std::string& b) {
return a.size() < b.size();
});
if (max_it != words.end()) {
std::cout << "Longest word: " << *max_it << std::endl; // 输出: Longest word: banana
}
return 0;
}
示例 4:查找最大绝对值
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath> // 包含 abs
int main() {
std::vector<int> nums = {-3, 1, -4, 1, 5, -9, 2, 6};
// 查找绝对值最大的元素
auto max_it = std::max_element(nums.begin(), nums.end(), [](int a, int b) {
return std::abs(a) < std::abs(b);
});
if (max_it != nums.end()) {
std::cout << "Max absolute value: " << *max_it << std::endl; // 输出: Max absolute value: -9
}
return 0;
}
注意事项
-
返回值:
std::max_element
返回指向最大元素的迭代器。如果范围为空,返回last
。- 如果需要获取最大元素的值,可以通过解引用迭代器(如
*max_it
)。
-
自定义比较函数:
- 比较函数
comp
必须满足严格弱序(strict weak ordering)。 - 比较函数的形式为
bool comp(const T& a, const T& b)
,如果a
小于b
,则返回true
。
- 比较函数
-
性能:
std::max_element
的时间复杂度是线性的,即 O(n),其中 n 是范围内元素的数量。
-
多个最大元素:
- 如果范围内有多个最大元素,
std::max_element
返回第一个最大元素的迭代器。
- 如果范围内有多个最大元素,
总结
std::max_element
是一个简单而强大的工具,用于查找范围内的最大元素。它支持自定义比较函数,可以灵活地适应各种查找需求。在实际开发中,合理使用 max_element
可以简化代码并提高效率。
std::reduce
在 C++ 中,std::reduce
是 C++17 引入的一个算法函数,定义在 <numeric>
头文件中。它用于对一个范围内的元素进行归约操作(即累积计算),类似于 std::accumulate
,但具有更高的并行化潜力。
函数原型
std::reduce
有多个重载版本,以下是两个常用的版本:
-
基本版本:
template<class InputIt> typename std::iterator_traits<InputIt>::value_type reduce(InputIt first, InputIt last);
first
和last
:定义了一个范围[first, last)
,表示要处理的元素。- 返回值:范围内所有元素的累加结果(默认使用加法操作)。
-
带初始值和自定义操作的版本:
template<class InputIt, class T, class BinaryOp> T reduce(InputIt first, InputIt last, T init, BinaryOp op);
first
和last
:定义了一个范围[first, last)
,表示要处理的元素。init
:初始值。op
:一个二元操作函数(或函数对象),用于定义如何累积元素。- 返回值:范围内所有元素根据
op
操作累积的结果。
基本用法
示例 1:累加整数
#include <iostream>
#include <numeric> // 包含 reduce
#include <vector>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
// 计算累加和
int sum = std::reduce(nums.begin(), nums.end());
std::cout << "Sum: " << sum << std::endl; // 输出: Sum: 15
return 0;
}
示例 2:累加浮点数
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<double> nums = {1.1, 2.2, 3.3, 4.4, 5.5};
// 计算累加和,初始值为 0.0
double sum = std::reduce(nums.begin(), nums.end(), 0.0);
std::cout << "Sum: " << sum << std::endl; // 输出: Sum: 16.5
return 0;
}
自定义操作
std::reduce
的第二个版本允许你自定义归约操作。你可以传递一个二元函数(或 lambda 表达式)来定义如何累积元素。
示例 3:累乘
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
// 计算累乘积,初始值为 1
int product = std::reduce(nums.begin(), nums.end(), 1, [](int a, int b) {
return a * b;
});
std::cout << "Product: " << product << std::endl; // 输出: Product: 120
return 0;
}
示例 4:连接字符串
#include <iostream>
#include <numeric>
#include <vector>
#include <string>
int main() {
std::vector<std::string> words = {"Hello", " ", "World", "!"};
// 连接字符串,初始值为空字符串
std::string result = std::reduce(words.begin(), words.end(), std::string(""), [](const std::string& a, const std::string& b) {
return a + b;
});
std::cout << "Concatenated: " << result << std::endl; // 输出: Concatenated: Hello World!
return 0;
}
与 std::accumulate
的区别
-
并行化支持:
std::reduce
允许并行执行,适合在并行环境中使用。std::accumulate
是严格顺序执行的。
-
操作顺序:
std::reduce
不保证操作的顺序,因此要求操作必须是可结合(associative)的。std::accumulate
严格按照顺序执行操作。
-
初始值:
std::reduce
的初始值是可选的,如果不提供初始值,则使用范围的第一个元素作为初始值。std::accumulate
必须提供初始值。
注意事项
-
操作的可结合性:
std::reduce
要求操作必须是可结合的(即(a op b) op c == a op (b op c)
),因为它的执行顺序是不确定的。
-
初始值类型:
- 初始值
init
的类型决定了reduce
的返回类型。
- 初始值
-
空范围:
- 如果范围
[first, last)
为空,std::reduce
会返回初始值init
(如果提供了初始值),否则行为未定义。
- 如果范围
总结
std::reduce
是一个强大的工具,用于对范围内的元素进行归约操作。它支持自定义操作,并且具有并行化潜力,适合在高性能计算中使用。与 std::accumulate
相比,std::reduce
更灵活,但需要确保操作是可结合的。在实际开发中,合理使用 std::reduce
可以简化代码并提高性能。