std::sort + std::unique 是最常用且高效的做法:先排序使重复元素相邻,再用 std::unique 移动去重后元素至前端并返回新逻辑结尾迭代器,最后必须调用 erase 才能真正缩容;若未排序则仅去相邻重复,不排序或漏 erase 均无效。

用 std::sort + std::unique 是最常用且高效的做法
直接调用 std::unique 不会真正删除元素,它只是把重复项移到末尾,并返回新逻辑结尾的迭代器;必须配合 erase 才能真正缩容。前提是 vector 必须已排序,否则 std::unique 只能去相邻重复项。
常见错误是漏掉排序或忘记 erase:
- 只写
std::unique(v.begin(), v.end())→ vector 大小不变,重复元素还在原位置 - 没排序就用
unique→[1,2,1]会变成[1,2,1](不生效)
正确写法:
std::sort(v.begin(), v.end()); v.erase(std::unique(v.begin(), v.end()), v.end());
时间复杂度 O(n log n),适用于大多数场景;如果原始顺序必须保留,这个方案就不适用。
要保持原始顺序时,用 std::unordered_set 遍历过滤
这是唯一能稳定保留首次出现顺序的方法。核心思路:遍历 vector,用哈希集合记录已见过的值,只保留未见过的元素。
注意点:
- 需要可哈希类型(
int、std::string等默认支持;自定义类需提供hash和==) - 空间开销多一个 O(n) 的哈希表
- 不能用
std::set替代(红黑树,O(n log n) 更慢)
示例:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
std::unordered_set<int> seen;
auto new_end = std::remove_if(v.begin(), v.end(), [&seen](int x) {
if (seen.count(x)) return true;
seen.insert(x);
return false;
});
v.erase(new_end, v.end());
</int>
遇到自定义结构体时,std::unique 要重载 operator==
std::unique 默认用 == 比较相邻元素,所以结构体必须定义该运算符,否则编译失败。
例如:
struct Point {
int x, y;
bool operator==(const Point& other) const {
return x == other.x && y == other.y;
}
};
然后才能排序 + unique:
std::sort(v.begin(), v.end(), [](const Point& a, const Point& b) {
return a.x
<p>别忘了排序逻辑也要和 <code>==</code> 语义一致,否则 unique 行为不可预测。</p>
<h3>性能和稳定性差异:什么时候选哪种?</h3>
<p>排序 + unique 适合大数据量、不要求顺序、元素类型简单(如 <code>int</code>、<code>double</code>)的场景;unordered_set 过滤适合中小数据量、必须保序、或有哈希支持的类型。</p>
<p>容易被忽略的一点:如果 vector 元素本身很大(比如含大数组或字符串),用 <code>remove_if</code> + <code>unordered_set</code> 会频繁拷贝,这时建议改用索引收集再重构 vector,避免移动成本。</p>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










