std::unique仅移除相邻重复元素,使用前必须先排序;若需去重且保持原序,应配合unordered_set遍历;对自定义类型须重载operator==及operator

std::unique 不能直接去重,必须先排序
std::unique 不是“去重函数”,它只移除相邻重复元素。如果 vector 未排序,std::unique 会漏掉非相邻的重复项。比如 {1,2,1} 经 std::unique 后仍是 {1,2,1} —— 因为两个 1 不相邻。
正确做法是:先用 std::sort 排序,再用 std::unique + erase 组合:
std::vectorv = {3, 1, 4, 1, 5, 9, 2, 6, 5}; std::sort(v.begin(), v.end()); // → {1,1,2,3,4,5,5,6,9} auto last = std::unique(v.begin(), v.end()); // 返回新逻辑尾迭代器 v.erase(last, v.end()); // 真正删除重复元素
注意:std::unique 不改变容器大小,只把重复元素“挤到末尾”,并返回指向新逻辑结尾的迭代器。
用 std::set 或 std::unordered_set 做无序去重
如果不需要保持原始顺序,且元素可比较(set)或可哈希(unordered_set),直接构造集合最简洁:
立即学习“C++免费学习笔记(深入)”;
std::vectorv = {3, 1, 4, 1, 5, 9, 2, 6, 5}; std::set s(v.begin(), v.end()); std::vector unique_v(s.begin(), s.end()); // 自动升序
若需保留首次出现顺序(如 {3,1,4,1,5} → {3,1,4,5}),用 std::unordered_set 辅助遍历:
std::vectorv = {3, 1, 4, 1, 5, 9, 2, 6, 5}; std::unordered_set seen; std::vector unique_v; for (int x : v) { if (seen.insert(x).second) { // insert 返回 pair ,second 为 true 表示新插入 unique_v.push_back(x); } }
std::unique 对自定义类型要重载 operator==
std::unique 默认用 operator== 判断相等。对结构体或类,必须显式定义该运算符,否则编译失败或行为未定义:
struct Point {
int x, y;
bool operator==(const Point& other) const {
return x == other.x && y == other.y;
}
};
同时,若配合 std::sort 使用,还需提供 operator 或自定义比较器,否则 sort 无法比较。
常见错误:只重载 == 却忘了 ,导致 sort 编译不过;或者重载了但没加 const 和引用,引发临时对象绑定问题。
性能与语义差异:别为了“看起来短”选错方案
-
sort + unique + erase:时间复杂度O(n log n),空间O(1)(原地),适合大数组且允许重排 -
unordered_set遍历去重:时间O(n),空间O(n),保留顺序,但哈希开销和内存占用略高 -
std::set构造:时间O(n log n),空间O(n),结果有序但丢失原序,且比sort+unique慢(因每次插入都做树平衡)
最容易被忽略的一点:所有基于 std::unique 的方案都依赖“相邻性”,而相邻性由你控制——要么靠 sort,要么靠预处理(比如按某字段分组后单独去重)。没意识到这点,就容易在调试时花几小时找“为什么还剩重复”。











