目 录CONTENT

文章目录

C++ STL:算法-变动算法

TalentQ
2025-09-01 / 0 评论 / 0 点赞 / 10 阅读 / 0 字

引言

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算法更安全、可读性更高,并支持自定义类型。

0

评论区