copy、fill、replace、unique —— 批量改写容器内容的通用算法。
把一段区间的元素逐个复制到另一个位置。目标位置需要预先分配好足够的空间——copy 不会自动帮目标容器扩容,只是简单地逐个赋值。
| 1 | vector<int> src = {1, 2, 3, 4, 5}; |
| 2 | vector<int> dst(5); // 目标容器需要预先分配空间 |
| 3 | copy(src.begin(), src.end(), dst.begin()); |
| 4 | // dst 变成 {1, 2, 3, 4, 5} |
dst 是一个空的 vector(没有预分配空间),直接 copy 会越界访问、导致未定义行为。正确做法是先 dst.resize(src.size()) 或者在定义时就给够大小,就像例子里 vector<int> dst(5) 那样。把指定区间内的全部元素都设为同一个值,可以填充整个容器,也可以只填充一部分。
| 1 | vector<int> v(5); |
| 2 | fill(v.begin(), v.end(), 42); |
| 3 | // v 变成 {42, 42, 42, 42, 42} |
| 4 | |
| 5 | // 填充前 3 个 |
| 6 | fill(v.begin(), v.begin() + 3, 7); |
| 7 | // v 变成 {7, 7, 7, 42, 42} |
vector 整体清零或者初始化成某个固定值时,fill 比手写 for 循环更简洁。如果只需要清零,memset(C 风格)也能做到,但 fill 对任意类型都适用,更通用、更安全。把区间内所有等于某个值的元素,统一替换成另一个值。
| 1 | vector<int> v = {1, 2, 3, 2, 4}; |
| 2 | replace(v.begin(), v.end(), 2, 99); |
| 3 | // v 变成 {1, 99, 3, 99, 4} |
replace_if,第三个参数换成一个返回 bool 的判断函数,比如 replace_if(v.begin(), v.end(), [](int x){ return x < 0; }, 0) 把所有负数替换成 0。unique 把连续重复的元素只保留第一个,多余的"挤"到区间末尾,并返回新的"有效末尾"位置——但它不会真正删除元素,容器大小不变,需要配合 erase 才能真正缩短容器。
unique 返回的迭代器指向新末尾(绿色区域之后),灰色虚线格子是残留的脏数据,必须用 erase 删掉才算真正去重完成。| 1 | vector<int> v = {1, 2, 2, 3, 3, 3, 4}; |
| 2 | // unique 把重复元素移到末尾,返回新末尾的迭代器 |
| 3 | auto new_end = unique(v.begin(), v.end()); |
| 4 | v.erase(new_end, v.end()); // 真正删除多余元素 |
| 5 | // v 变成 {1, 2, 3, 4} |
unique 只移除连续重复的元素。如果元素是分散的(比如 {1, 2, 1, 3, 1}),unique 不会把三个 1 都去掉——需要先 sort 再 unique,让相同的元素先挨在一起,才能正确去重。这是竞赛里"排序去重"的标准三连招:sort → unique → erase。