std::unique仅重排相邻重复元素并返回新逻辑结尾,不真正删除;必须配合erase才能缩容,且要求输入已排序或相同元素相邻。

unique 函数本身不真正删除元素,只重排
std::unique 不是“去重函数”,它只把相邻重复元素移到容器末尾,并返回一个迭代器指向新逻辑结尾。原 vector 大小不变,内存里仍存着旧值。
常见错误是只调用 std::unique 就以为完成去重:
std::vectorv = {1, 2, 2, 3, 3, 3, 4}; std::unique(v.begin(), v.end()); // ❌ 没用!v.size() 还是 7
必须配合 erase 才能真正删掉冗余:
std::vectorv = {1, 2, 2, 3, 3, 3, 4}; auto new_end = std::unique(v.begin(), v.end()); v.erase(new_end, v.end()); // ✅ 此时 v = {1, 2, 3, 4}
-
std::unique要求输入已排序(或至少相同元素相邻),否则只去“连续重复” - 它比较的是
*it和*(it-1),不是和首元素比 - 对
vector或自定义类型,需确保operator==可用,或传入二元谓词
去重前必须 sort,否则结果不可靠
如果原始 vector 是乱序的,比如 {3, 1, 2, 1, 3},直接 unique 得到的是 {3, 1, 2, 1, 3}(因为没相邻重复),根本没效果。
立即学习“C++免费学习笔记(深入)”;
正确流程是先 sort 再 unique + erase:
动态WEB网站中的PHP和MySQL详细反映实际程序的需求,仔细地探讨外部数据的验证(例如信用卡卡号的格式)、用户登录以及如何使用模板建立网页的标准外观。动态WEB网站中的PHP和MySQL的内容不仅仅是这些。书中还提到如何串联JavaScript与PHP让用户操作时更快、更方便。还有正确处理用户输入错误的方法,让网站看起来更专业。另外还引入大量来自PEAR外挂函数库的强大功能,对常用的、强大的包
std::vectorv = {3, 1, 2, 1, 3}; std::sort(v.begin(), v.end()); // → {1, 1, 2, 3, 3} auto it = std::unique(v.begin(), v.end()); // → {1, 2, 3, 3, 3} v.erase(it, v.end()); // → {1, 2, 3}
-
std::sort默认升序;如需保持原顺序去重,不能用unique,得换哈希法 - 对含浮点数的
vector,慎用==判断相等,unique可能因精度失效 -
sort + unique时间复杂度 O(n log n),空间 O(1),适合内存敏感但允许重排的场景
保持原顺序去重:用 unordered_set 记录已见元素
当必须保留首次出现顺序(如 {3, 1, 2, 1, 3} → {3, 1, 2}),sort + unique 不适用,得边遍历边过滤。
典型做法是用 std::unordered_set 缓存已出现的值,只保留第一次遇到的:
std::vectorv = {3, 1, 2, 1, 3}; std::unordered_set seen; std::vector result; for (int x : v) { if (seen.find(x) == seen.end()) { seen.insert(x); result.push_back(x); } } // result = {3, 1, 2}
- 此法时间复杂度平均 O(n),空间 O(n),适用于中等规模数据
- 注意
unordered_set对自定义类型需提供hash和operator== - 如果只是“判断是否存在”,别用
count(),find()更快(避免二次查找) - 想原地修改?可以反向遍历 +
erase,但多次erase在中间位置性能差,不推荐
unique_copy 避免修改原 vector,但需预分配空间
如果不想动原 vector,又不想手写循环,std::unique_copy 是更干净的选择 —— 它把去重后结果拷到另一容器。
但注意:目标容器必须有足够空间,或用插入迭代器:
std::vectorsrc = {1, 1, 2, 2, 3, 3}; std::vector dst; // 方法1:用 back_inserter(推荐,自动扩容) std::unique_copy(src.begin(), src.end(), std::back_inserter(dst)); // 方法2:预分配大小(需先 sort) std::sort(src.begin(), src.end()); dst.resize(src.size()); auto end_it = std::unique_copy(src.begin(), src.end(), dst.begin()); dst.erase(end_it, dst.end());
-
unique_copy同样要求输入已排序(或相邻重复)才能正确去重 - 用
back_inserter最安全,但每次push_back可能触发多次内存重分配 - 若确定最大可能大小,预分配 +
resize+erase更高效










