std::unique不能直接去重,因为它仅移除相邻重复元素并返回新逻辑末尾,不改变容器实际大小,需配合erase才能真正删除;对未排序序列无效,原生数组需双指针手动覆盖实现就地去重。

std::unique 为什么不能直接去重?
std::unique 只把相邻重复元素“挤到后面”,并不真正删除——它只是重排数组,返回一个新末尾迭代器。如果你直接用 std::unique 后不配合 erase,数组长度没变,后面还残留着旧值。
- 必须搭配容器的
erase才算真正移除(如vec.erase(std::unique(vec.begin(), vec.end()), vec.end())) -
std::unique要求输入已排序,否则只删相邻重复项,漏掉跨位置的重复(比如{1,2,1}经unique后仍是{1,2,1}) - 对原生数组(
int arr[N])无法直接调用erase,得手动计算新长度或复制到新容器
用 std::set 或 std::unordered_set 去重并保持顺序?
如果要保留首次出现顺序且彻底去重,std::unordered_set 是更合适的选择:查重 O(1),插入时跳过已有元素。但注意它不保证遍历顺序——所以得额外用 vector 记录顺序。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 典型写法:
std::vector<int> result; std::unordered_set<int> seen; for (int x : input) { if (seen.insert(x).second) result.push_back(x); }</int></int> -
seen.insert(x).second返回true表示是新元素,避免二次查找 - 若输入含自定义类型,需提供
hash和==,否则编译不过 - 内存开销比原地操作大,但逻辑清晰、不易出错
原生数组怎么安全地“就地”去重?
原生数组没有 erase,只能靠双指针手动覆盖。关键点是:读指针扫全部,写指针只在遇到新元素时前进并赋值。
- 示例代码:
int write = 0; for (int read = 0; read
- 时间复杂度 O(n²),适合小数组;大数据量建议先排序再用
unique+ 手动截断 - 别忘了最后用
write当作新长度用,原数组后半段仍是脏数据
排序 + unique 是最常用组合,但要注意副作用
排序会改变原始顺序,如果业务允许,这是最简洁可靠的方案。关键是别漏掉 erase 步骤,尤其在 vector 上。
- 正确写法:
std::sort(v.begin(), v.end()); v.erase(std::unique(v.begin(), v.end()), v.end()); - 对
std::vector有效;对std::array或裸数组,erase不可用,得用std::unique返回的迭代器减去开头算出新长度 - 如果元素类型不可比较(比如没有
),<code>sort编译失败,这时只能退回哈希方案
unique 自带删除功能。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










