std::unique 不真正删除元素,仅将重复项移至末尾并返回新逻辑结尾迭代器;必须配合 erase 使用,且要求数据已排序才能全局去重,否则只去除相邻重复项。

为什么直接用 std::unique 删不掉重复元素?
std::unique 不是真的删除元素,它只是把重复项“挤到末尾”,并返回一个指向新逻辑结尾的迭代器。原 vector 大小不变,内存里那些重复值还留着——如果你不配合 erase,根本看不出来效果。
- 常见错误:只写
std::unique(v.begin(), v.end()),没接erase - 必须和
erase配合:v.erase(std::unique(v.begin(), v.end()), v.end()) -
unique要求数据已排序,否则只去相邻重复项(比如{1,2,1}经unique后仍是{1,2,1})
必须先 sort 吗?什么情况下可以跳过?
要看你对“重复”的定义。如果只要求去除**相邻重复项**(比如日志流中连续重复上报),那不用 sort;但绝大多数场景要的是“全局去重”,就必须先 sort。
-
sort + unique + erase时间复杂度是O(n log n),适合大多数情况 - 如果原数据基本有序,可考虑
std::unique单独用,省掉sort开销 - 如果不能改变原始顺序(如需保序去重),
sort就不可行,得换哈希表或遍历标记
unique 的比较函数怎么写?支持自定义类型吗?
支持。传入第三个参数即可,它是个二元谓词,返回 true 表示“视为相等”。注意:这个函数只用于判断“是否该被去重”,不影响 sort 的排序逻辑。
- 基础类型可省略,比如
unique(v.begin(), v.end()) - 自定义结构体:
unique(v.begin(), v.end(), [](const auto& a, const auto& b) { return a.id == b.id; }) - 注意:即使用了自定义比较,
sort仍需单独调用,且它的比较逻辑要和unique一致,否则行为未定义 - 字符串忽略大小写去重:
sort(v.begin(), v.end(), [](const string& a, const string& b) { return strcasecmp(a.c_str(), b.c_str()) ,然后同理传给 <code>unique
性能和边界问题:空 vector、含 NaN、指针 vector 怎么办?
这些地方容易崩或出逻辑错,不是语法报错,而是运行时行为异常或结果不符合预期。
- 空
vector或单元素:sort和unique都安全,可直接调用 -
double类型含NaN:sort可能抛异常或结果不确定(NaN不满足严格弱序),建议预处理过滤或用std::isfinite排除 - 指针
vector<t></t>:unique比较的是地址值,不是所指对象内容;若想按对象内容去重,得自己写比较函数,并确保指针非空 - 迭代器失效风险:所有操作都在原容器上进行,中间别用其他线程修改该
vector
erase 那一截,或者忘了 sort 前提。保序、NaN、指针这三类情况,光靠 sort + unique 解不了,得提前判断场景。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











