C++中std::unique_copy怎么去重连续元素_C++标准库算法操作方法【笔记】

4次阅读

std::unique_copy仅去除相邻重复元素且不修改原容器;需源区间已排序或接受仅去重连续块语义,目标区间须预分配空间并用返回迭代器截断。

C++中std::unique_copy怎么去重连续元素_C++标准库算法操作方法【笔记】

std::unique_copy 只能去除相邻重复元素,不能全局去重;它不修改原容器,而是把去重结果复制到目标区间

std::unique_copy 的作用范围和前提条件

这个函数只识别并跳过「紧挨着的重复项」,比如 {1,2,2,3,3,3,4} 会变成 {1,2,3,4},但 {1,2,3,2,4} 中的第二个 2 不会被删——因为它前面是 3,不连续。

  • 输入迭代器必须支持前向遍历(至少是 ForwardIterator)
  • 源区间必须已按某种规则排好序,或你明确接受“仅去重连续块”的语义
  • 目标容器/区间要有足够空间容纳输出(返回值是目标末尾迭代器,务必用它来截断)

正确调用 std::unique_copy 的三要素

常见错误是忽略返回值、没预留空间、或误以为它会自动 shrink 目标容器。实际需手动处理长度:

std::vector src = {1,1,2,2,2,3,4,4}; std::vector dst(src.size()); // 预分配,避免 reallocate 影响迭代器有效性 auto last = std::unique_copy(src.begin(), src.end(), dst.begin()); dst.erase(last, dst.end()); // 关键:用返回的迭代器清理多余元素
  • 第三个参数是目标起始位置,不是容器本身
  • 返回值是「写入结束位置」,类型与第三个参数相同(这里是 dst.begin() 类型)
  • 如果目标是 raw Arraystd::array,不能调 erase,得自己记下长度

配合自定义比较逻辑的注意事项

默认用 operator==,但可通过第四个参数传入二元谓词。注意:该谓词仍只比较相邻元素,且必须满足等价关系(自反、对称、传递),否则行为未定义:

立即学习C++免费学习笔记(深入)”;

// 忽略大小写的字符串去重(连续) std::vector words = {"Hello", "HELLO", "world", "WORLD", "hello"}; std::vector uniq; uniq.resize(words.size()); auto last = std::unique_copy(words.begin(), words.end(), uniq.begin(),     [](const std::string& a, const std::string& b) {         return std::equal(a.begin(), a.end(), b.begin(), b.end(),             [](char x, char y) { return std::tolower(x) == std::tolower(y); });     }); uniq.erase(last, uniq.end());
  • 谓词接收的是「当前元素」和「前一个元素」,顺序固定为 (prev, curr)
  • 不能在里面修改元素,也不能抛异常(c++17 起要求谓词是 noexcept)
  • 如果源数据没按该谓词“等价”分组,结果不可预测(例如先小写后大写混排)

和 std::unique 的关键区别在哪

最常混淆的点:两者语义不同,适用场景也不同。

  • std::unique 在原容器上操作,返回「新逻辑末尾」,需配合 erase 才真正缩容;std::unique_copy 完全不碰源数据
  • std::unique 要求双向迭代器(因要 erase),std::unique_copy 只需前向迭代器
  • 如果目标是输出到 ostream_iterator 或 transform 后再复制,只能用 unique_copy
  • 性能上,unique_copy 多一次内存拷贝,但避免了原容器的移动/赋值开销

连续去重这件事本身很简单,难的是意识到它不解决「重复元素散落各处」的问题——真要全局唯一,得先排序或换用 std::set / std::unordered_set 做标记。

text=ZqhQzanResources