跳到主要内容

C++ 修改序列操作

在C++的STL(标准模板库)中,修改序列操作是一组能够修改容器内元素的算法。这些算法可以帮助我们对序列进行复制、替换、填充、删除等操作,大大简化了对容器内元素的处理。本文将详细介绍这些修改序列操作的使用方法和实际应用场景。

修改序列操作概述

修改序列操作主要位于<algorithm>头文件中,它们接受迭代器作为参数,对迭代器指向的序列进行修改。常用的修改序列操作包括:

  1. 复制操作copy, copy_if, copy_n, copy_backward
  2. 替换操作replace, replace_if, replace_copy
  3. 填充操作fill, fill_n, generate, generate_n
  4. 移除操作remove, remove_if, remove_copy
  5. 独特化操作unique, unique_copy
  6. 交换和重排操作swap, iter_swap, swap_ranges, reverse, rotate

复制操作

复制操作是最基础的序列修改操作,用于将一个序列的元素复制到另一个序列中。

copy

copy算法将一个范围内的元素复制到另一个位置:

cpp
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> destination(5);

// 将source中的元素复制到destination中
std::copy(source.begin(), source.end(), destination.begin());

// 打印destination中的元素
for (int num : destination) {
std::cout << num << " ";
}
// 输出: 1 2 3 4 5

return 0;
}

copy_if

copy_if算法根据指定条件将元素复制到另一个位置:

cpp
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> source = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::vector<int> destination;

// 预留空间以提高效率
destination.reserve(source.size());

// 将source中的偶数复制到destination中
std::copy_if(source.begin(), source.end(),
std::back_inserter(destination),
[](int n) { return n % 2 == 0; });

// 打印destination中的元素
for (int num : destination) {
std::cout << num << " ";
}
// 输出: 2 4 6 8 10

return 0;
}
提示

使用std::back_inserter创建一个插入迭代器,每次赋值时都会在容器末尾插入新元素,避免了预先分配空间大小的问题。

替换操作

替换操作用于将序列中满足特定条件的元素替换为新值。

replace

replace算法将序列中所有等于给定值的元素替换为新值:

cpp
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> numbers = {1, 2, 3, 2, 5, 2, 7, 8};

// 将所有2替换为20
std::replace(numbers.begin(), numbers.end(), 2, 20);

// 打印替换后的结果
for (int num : numbers) {
std::cout << num << " ";
}
// 输出: 1 20 3 20 5 20 7 8

return 0;
}

replace_if

replace_if算法将序列中所有满足谓词条件的元素替换为新值:

cpp
#include <iostream>
#include <vector>
#include <algorithm>

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

// 将所有偶数替换为0
std::replace_if(numbers.begin(), numbers.end(),
[](int n) { return n % 2 == 0; }, 0);

// 打印替换后的结果
for (int num : numbers) {
std::cout << num << " ";
}
// 输出: 1 0 3 0 5 0 7 0

return 0;
}

填充操作

填充操作用于将特定值或者根据生成器函数的结果填充到序列中。

fill

fill算法将指定的值填充到指定范围的每个元素:

cpp
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> numbers(5);

// 将向量中的所有元素设置为10
std::fill(numbers.begin(), numbers.end(), 10);

// 打印结果
for (int num : numbers) {
std::cout << num << " ";
}
// 输出: 10 10 10 10 10

return 0;
}

generate

generate算法将生成器函数的结果填充到指定范围的每个元素:

cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>

int main() {
std::vector<int> numbers(5);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 100);

// 用随机数填充向量
std::generate(numbers.begin(), numbers.end(), [&]() { return dis(gen); });

// 打印结果
for (int num : numbers) {
std::cout << num << " ";
}
// 输出: 例如 45 23 78 91 12 (随机数)

return 0;
}

移除操作

移除操作用于从序列中移除满足特定条件的元素。

警告

STL的移除操作并不会真正从容器中删除元素,它们只是将要保留的元素移动到序列的前部,并返回一个迭代器指向新的逻辑结尾。要真正删除元素,需要配合容器的erase方法使用。

remove

remove算法移除所有等于给定值的元素:

cpp
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> numbers = {1, 2, 3, 2, 5, 2, 7, 8};

// 移除所有值为2的元素
auto new_end = std::remove(numbers.begin(), numbers.end(), 2);

// 截断向量,真正删除元素
numbers.erase(new_end, numbers.end());

// 打印结果
for (int num : numbers) {
std::cout << num << " ";
}
// 输出: 1 3 5 7 8

return 0;
}

remove_if

remove_if算法移除所有满足谓词条件的元素:

cpp
#include <iostream>
#include <vector>
#include <algorithm>

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

// 移除所有偶数
auto new_end = std::remove_if(numbers.begin(), numbers.end(),
[](int n) { return n % 2 == 0; });

// 截断向量,真正删除元素
numbers.erase(new_end, numbers.end());

// 打印结果
for (int num : numbers) {
std::cout << num << " ";
}
// 输出: 1 3 5 7

return 0;
}

独特化操作

独特化操作用于移除序列中的重复元素,使序列中的每个元素都是唯一的。

unique

unique算法移除序列中连续的重复元素(序列应该事先已排序):

cpp
#include <iostream>
#include <vector>
#include <algorithm>

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

// 移除连续重复元素
auto new_end = std::unique(numbers.begin(), numbers.end());

// 截断向量
numbers.erase(new_end, numbers.end());

// 打印结果
for (int num : numbers) {
std::cout << num << " ";
}
// 输出: 1 2 3 4 5

return 0;
}
注意

unique只能移除相邻的重复元素。如果想要移除所有重复元素,先使用sort排序,再使用unique

交换和重排操作

交换和重排操作用于改变序列中元素的顺序。

swap

swap算法交换两个变量的值:

cpp
#include <iostream>
#include <algorithm>

int main() {
int a = 5, b = 10;

std::cout << "Before swap: a = " << a << ", b = " << b << std::endl;

// 交换a和b的值
std::swap(a, b);

std::cout << "After swap: a = " << a << ", b = " << b << std::endl;
// 输出: After swap: a = 10, b = 5

return 0;
}

reverse

reverse算法将指定范围内的元素顺序反转:

cpp
#include <iostream>
#include <vector>
#include <algorithm>

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

// 反转序列
std::reverse(numbers.begin(), numbers.end());

// 打印结果
for (int num : numbers) {
std::cout << num << " ";
}
// 输出: 5 4 3 2 1

return 0;
}

rotate

rotate算法将序列中的元素进行旋转:

cpp
#include <iostream>
#include <vector>
#include <algorithm>

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

// 将序列旋转,使第3个元素(索引2)成为第一个元素
std::rotate(numbers.begin(), numbers.begin() + 2, numbers.end());

// 打印结果
for (int num : numbers) {
std::cout << num << " ";
}
// 输出: 3 4 5 1 2

return 0;
}

实际应用案例

案例1:数据过滤与转换

假设我们有一个学生成绩数据库,需要筛选出所有及格的学生(分数≥60)并将他们的分数提高5分作为奖励:

cpp
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

struct Student {
std::string name;
int score;

Student(const std::string& n, int s) : name(n), score(s) {}
};

int main() {
// 学生数据
std::vector<Student> allStudents = {
{"Alice", 85}, {"Bob", 45}, {"Charlie", 90},
{"David", 55}, {"Eve", 75}, {"Frank", 60}
};

std::vector<Student> passedStudents;

// 筛选及格学生(分数≥60)
std::copy_if(allStudents.begin(), allStudents.end(),
std::back_inserter(passedStudents),
[](const Student& s) { return s.score >= 60; });

// 给及格学生加5分奖励(最高不超过100分)
std::for_each(passedStudents.begin(), passedStudents.end(),
[](Student& s) { s.score = std::min(s.score + 5, 100); });

// 打印结果
std::cout << "及格学生名单(加分后):\n";
for (const auto& student : passedStudents) {
std::cout << student.name << ": " << student.score << std::endl;
}

return 0;
}

输出:

及格学生名单(加分后):
Alice: 90
Charlie: 95
Eve: 80
Frank: 65

案例2:文本处理

假设我们需要处理一段文本,移除所有标点符号并将所有单词转换为小写:

cpp
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

int main() {
std::string text = "Hello, World! This is a C++ Program. Isn't it AMAZING?";

// 将所有大写字母转换为小写
std::transform(text.begin(), text.end(), text.begin(),
[](unsigned char c) { return std::tolower(c); });

// 移除标点符号和空格
auto newEnd = std::remove_if(text.begin(), text.end(),
[](unsigned char c) {
return std::ispunct(c) || std::isspace(c);
});
text.erase(newEnd, text.end());

std::cout << "处理后的文本:" << text << std::endl;

return 0;
}

输出:

处理后的文本:helloworldthisisacprogramisntitamazing

总结

C++ STL提供的修改序列操作是处理容器内元素的强大工具:

  1. 复制操作(如copy, copy_if)可以方便地复制元素。
  2. 替换操作(如replace, replace_if)可以替换满足特定条件的元素。
  3. 填充操作(如fill, generate)可以用特定值填充序列。
  4. 移除操作(如remove, remove_if)可以移除满足特定条件的元素。
  5. 独特化操作(如unique)可以移除重复元素。
  6. 交换和重排操作(如swap, reverse, rotate)可以改变元素位置。

这些算法大大简化了元素处理的代码量,提高了代码的可读性和效率。熟练掌握这些操作将让你的C++编程更加高效。

练习题

  1. 编写一个程序,使用replace_if将向量中所有负数替换为0。
  2. 使用remove_copy_ifback_inserter,将一个字符串中的元音字母复制到另一个字符串中。
  3. 编写一个程序,使用unique移除已排序数组中的所有重复元素。
  4. 使用rotate实现一个简单的循环队列。

参考资源