引言
C++标准模板库(STL)中的变动算法(Mutating Algorithms)是指会改变容器内容或输出结果的算法。这些算法极大地提升了代码的可读性、效率和安全性。
1 copy、copy_if、copy_n
1.1 copy
原理:将一个区间内的元素复制到另一个区间,目标区间必须有足够空间。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
// 将v1复制到v2
void CopyExample() {
std::vector<int> v1{1, 2, 3, 4, 5};
std::vector<int> v2(5);
std::copy(v1.begin(), v1.end(), v2.begin());
// v2: 1 2 3 4 5
}
适用场景:需要完整复制容器内容时。
对比:与 std::memcpy 不同,copy 能处理非POD类型,支持自定义类型的拷贝构造。
1.2 copy_if
原理:将满足条件的元素复制到目标区间。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
void CopyIfExample() {
std::vector<int> v1{1, 2, 3, 4, 5};
std::vector<int> v2;
std::copy_if(v1.begin(), v1.end(), std::back_inserter(v2),
[](int x) { return x % 2 == 0; });
// v2: 2 4
}
适用场景:只需复制满足特定条件的元素。
1.3 copy_n
原理:复制前n个元素。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
void CopyNExample() {
std::vector<int> v1{1, 2, 3, 4, 5};
std::vector<int> v2(3);
std::copy_n(v1.begin(), 3, v2.begin());
// v2: 1 2 3
}
适用场景:只复制前N个元素。
2 move
原理:将元素“移动”到目标区间,原区间元素被置于有效但未指定状态。
用法:
#include <algorithm>
#include <vector>
#include <string>
void MoveExample() {
std::vector<std::string> v1{"a", "b", "c"};
std::vector<std::string> v2(3);
std::move(v1.begin(), v1.end(), v2.begin());
// v2: "a" "b" "c"
// v1: "" "" ""
}
适用场景:需要高效转移资源所有权,避免不必要的拷贝。
对比:比 copy 更快(对于可移动类型),但原对象不可再用。
3 swap、swap_ranges
3.1 swap
原理:交换两个对象的内容。
用法:
#include <algorithm>
#include <vector>
void SwapExample() {
int a = 1, b = 2;
std::swap(a, b); // a=2, b=1
}
适用场景:变量值交换。
3.2 swap_ranges
原理:交换两个区间的内容。
用法:
#include <algorithm>
#include <vector>
void SwapRangesExample() {
std::vector<int> v1{1, 2, 3}, v2{4, 5, 6};
std::swap_ranges(v1.begin(), v1.end(), v2.begin());
// v1: 4 5 6, v2: 1 2 3
}
适用场景:区间内容互换。
4 fill、fill_n
4.1 fill
原理:将区间所有元素赋为指定值。
用法:
#include <algorithm>
#include <vector>
void FillExample() {
std::vector<int> v(5);
std::fill(v.begin(), v.end(), 7);
// v: 7 7 7 7 7
}
适用场景:初始化或重置容器。
4.2 fill_n
原理:填充n个元素。
用法:
#include <algorithm>
#include <vector>
void FillNExample() {
std::vector<int> v(5);
std::fill_n(v.begin(), 3, 9);
// v: 9 9 9 0 0
}
5 transform
原理:对区间元素应用函数,结果写入目标区间。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
void TransformExample() {
std::vector<int> v1{1, 2, 3}, v2(3);
std::transform(v1.begin(), v1.end(), v2.begin(),
[](int x) { return x * x; });
// v2: 1 4 9
}
适用场景:批量修改元素(如映射、归一化等)。
对比:类似Python的map,但更高效且类型安全。
6 replace、replace_if、replace_copy、replace_copy_if
6.1 replace
原理:将等于old_value的元素替换为new_value。
用法:
#include <algorithm>
#include <vector>
void ReplaceExample() {
std::vector<int> v{1, 2, 2, 3};
std::replace(v.begin(), v.end(), 2, 8);
// v: 1 8 8 3
}
6.2 replace_if
原理:对满足条件的元素进行替换。
用法:
#include <algorithm>
#include <vector>
void ReplaceIfExample() {
std::vector<int> v{1, 2, 3, 4};
std::replace_if(v.begin(), v.end(), [](int x){ return x % 2 == 0; }, 0);
// v: 1 0 3 0
}
6.3 replace_copy
原理:替换后结果输出到新区间,原区间不变。
用法:
#include <algorithm>
#include <vector>
#include <iterator>
void ReplaceCopyExample() {
std::vector<int> v1{1, 2, 2, 3}, v2;
std::replace_copy(v1.begin(), v1.end(), std::back_inserter(v2), 2, 5);
// v2: 1 5 5 3
}
6.4 replace_copy_if
原理:条件替换,结果输出到新区间。
用法:
#include <algorithm>
#include <vector>
#include <iterator>
void ReplaceCopyIfExample() {
std::vector<int> v1{1, 2, 3, 4}, v2;
std::replace_copy_if(v1.begin(), v1.end(), std::back_inserter(v2),
[](int x){ return x > 2; }, 0);
// v2: 1 2 0 0
}
7 remove、remove_if、remove_copy、remove_copy_if
7.1 remove
原理:将等于value的元素“移除”到区间尾部,返回新逻辑结尾迭代器。实际并不缩减容器大小。
用法:
#include <algorithm>
#include <vector>
void RemoveExample() {
std::vector<int> v{1, 2, 3, 2, 4};
auto new_end = std::remove(v.begin(), v.end(), 2);
v.erase(new_end, v.end());
// v: 1 3 4
}
适用场景:移除元素,需配合容器的 erase 完成真正删除(即“erase-remove”惯用法)。
7.2 remove_if
原理:移除满足条件的元素。
用法:
#include <algorithm>
#include <vector>
void RemoveIfExample() {
std::vector<int> v{1, 2, 3, 4, 5};
auto new_end = std::remove_if(v.begin(), v.end(),
[](int x) { return x % 2 == 0; });
v.erase(new_end, v.end());
// v: 1 3 5
}
7.3 remove_copy
原理:移除指定值,结果输出到新区间。
用法:
#include <algorithm>
#include <vector>
#include <iterator>
void RemoveCopyExample() {
std::vector<int> v1{1, 2, 2, 3}, v2;
std::remove_copy(v1.begin(), v1.end(), std::back_inserter(v2), 2);
// v2: 1 3
}
7.4 remove_copy_if
原理:移除满足条件的元素,结果输出到新区间。
用法:
#include <algorithm>
#include <vector>
#include <iterator>
void RemoveCopyIfExample() {
std::vector<int> v1{1, 2, 3, 4}, v2;
std::remove_copy_if(v1.begin(), v1.end(), std::back_inserter(v2),
[](int x){ return x > 2; });
// v2: 1 2
}
8 unique、unique_copy
8.1 unique
原理:去除连续重复元素,将唯一元素移至前面,返回新逻辑结尾。
用法:
#include <algorithm>
#include <vector>
void UniqueExample() {
std::vector<int> v{1, 1, 2, 2, 3, 3, 3};
auto new_end = std::unique(v.begin(), v.end());
v.erase(new_end, v.end());
// v: 1 2 3
}
注意:只去除连续重复元素,通常需先排序。
8.2 unique_copy
原理:将唯一元素复制到新区间。
用法:
#include <algorithm>
#include <vector>
#include <iterator>
void UniqueCopyExample() {
std::vector<int> v1{1, 1, 2, 2, 3, 3}, v2;
std::unique_copy(v1.begin(), v1.end(), std::back_inserter(v2));
// v2: 1 2 3
}
9 reverse、reverse_copy
9.1 reverse
原理:原地反转区间。
用法:
#include <algorithm>
#include <vector>
void ReverseExample() {
std::vector<int> v{1, 2, 3};
std::reverse(v.begin(), v.end());
// v: 3 2 1
}
9.2 reverse_copy
原理:反转后复制到新区间。
用法:
#include <algorithm>
#include <vector>
#include <iterator>
void ReverseCopyExample() {
std::vector<int> v1{1, 2, 3}, v2;
std::reverse_copy(v1.begin(), v1.end(), std::back_inserter(v2));
// v2: 3 2 1
}
10 rotate、rotate_copy
10.1 rotate
原理:将区间 [first, middle) 移到 [middle, last) 后面。
用法:
#include <algorithm>
#include <vector>
void RotateExample() {
std::vector<int> v{1, 2, 3, 4, 5};
std::rotate(v.begin(), v.begin() + 2, v.end());
// v: 3 4 5 1 2
}
10.2 rotate_copy
原理:旋转后复制到新区间。
用法:
#include <algorithm>
#include <vector>
#include <iterator>
void RotateCopyExample() {
std::vector<int> v1{1, 2, 3, 4, 5}, v2;
std::rotate_copy(v1.begin(), v1.begin() + 2, v1.end(),
std::back_inserter(v2));
// v2: 3 4 5 1 2
}
11 partition、partition_copy、stable_partition
11.1 partition
原理:根据条件将区间分为两部分,满足条件的在前,顺序不保证。
用法:
#include <algorithm>
#include <vector>
void PartitionExample() {
std::vector<int> v{1, 2, 3, 4, 5};
std::partition(v.begin(), v.end(), [](int x){ return x % 2 == 0; });
// 前面是偶数,后面是奇数,顺序不保证
}
11.2 partition_copy
原理:分区后分别输出到两个新区间。
用法:
#include <algorithm>
#include <vector>
#include <iterator>
void PartitionCopyExample() {
std::vector<int> v{1, 2, 3, 4, 5}, evens, odds;
std::partition_copy(v.begin(), v.end(), std::back_inserter(evens),
std::back_inserter(odds), [](int x){ return x % 2 == 0; });
// evens: 2 4, odds: 1 3 5
}
11.3 stable_partition
原理:分区,且保持原相对顺序。
用法:
#include <algorithm>
#include <vector>
void StablePartitionExample() {
std::vector<int> v{1, 2, 3, 4, 5};
std::stable_partition(v.begin(), v.end(), [](int x){ return x % 2 == 0; });
// 顺序保持
}
12 shuffle
原理:使用随机数生成器随机打乱区间。
用法:
#include <algorithm>
#include <vector>
#include <random>
void ShuffleExample() {
std::vector<int> v{1, 2, 3, 4, 5};
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
// v被随机打乱
}
注意:C++11及以后推荐使用 std::shuffle,安全性高。
13 random_shuffle(C++14 之前)
原理:随机打乱区间,C++14及之前使用。
用法:
#include <algorithm>
#include <vector>
void RandomShuffleExample() {
std::vector<int> v{1, 2, 3, 4, 5};
std::random_shuffle(v.begin(), v.end());
// v被随机打乱
}
注意:已被C++17移除,建议用 std::shuffle 替代。
总结与扩展
STL变动算法极大提升了代码的表达力和效率,避免了手写循环和错误。
许多算法返回“新逻辑结尾”,需配合容器的
erase方法使用。变动算法适用于所有满足迭代器要求的容器,灵活且高效。
对比手写循环,STL算法更安全、可读性更高,并支持自定义类型。
评论区