std::set去重会丢失原始顺序;unordered_set配合vector可高效保留顺序;std::unique仅适用于已排序数组且需配合erase使用;c风格数组需手动管理长度并用双指针原地去重。

用 std::set 去重:最简单但会丢失顺序
如果你只关心元素唯一性,不care原始顺序,std::set 是最直接的选择。它自动排序且去重,插入即完成处理。
常见错误是直接把数组塞进 set 后就以为能按原顺序遍历——其实 set 是红黑树实现,遍历结果是升序的。
实操建议:
- 用
std::vector存原始数据,再用std::set<int>(vec.begin(), vec.end())</int>构造 - 若需转回数组,用
std::vector<int>(s.begin(), s.end())</int>拷贝 - 注意:
set插入复杂度是O(log n),整体O(n log n),不适合超大数组
用 std::unordered_set + 保留顺序:推荐通用方案
这是兼顾效率和顺序的实际首选。用哈希表判重,同时遍历原数组,只保留首次出现的元素。
容易踩的坑:
- 忘记初始化
unordered_set,或误用set导致意外排序 - 对自定义类型没提供
hash和==,编译报错:error: call to implicitly-deleted default constructor - 没预留 vector 容量,频繁 realloc 影响性能
示例(int 数组):
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
std::vector<int> arr = {1, 2, 2, 3, 1, 4};
std::unordered_set<int> seen;
std::vector<int> unique;
unique.reserve(arr.size()); // 避免重复扩容
for (int x : arr) {
if (seen.insert(x).second) { // insert 返回 pair<iter bool>,second 为 true 表示新插入
unique.push_back(x);
}
}</iter></int></int></int>
原地去重(std::unique):只适用于已排序数组
std::unique 不是真的删除元素,而是把重复项移到末尾,并返回新逻辑终点迭代器。它**要求输入必须已排序**,否则去重无效。
典型误用场景:
- 对乱序数组直接调
std::unique,结果看起来“没去重”——其实是它只移除相邻重复项 - 忘了配合
erase真删内存,只拿到迭代器就停了 - 对
std::array或 C 风格数组用错语法,比如写成std::unique(arr, arr + n)却没接返回值
正确用法(仅限已排序):
std::vector<int> v = {1, 1, 2, 2, 3, 3};
auto last = std::unique(v.begin(), v.end());
v.erase(last, v.end()); // 必须这一步才真正缩容</int>
对 C 风格数组去重:别硬套 STL 算法
C 风格数组(如 int arr[10])没有 size 信息,std::unique 可以用,但得手动传长度;而 unordered_set 方案必须额外记录有效长度,否则遍历越界。
实操要点:
- 永远传真实元素个数,别用
sizeof(arr)/sizeof(*arr)在函数参数里——数组退化为指针后失效 - 如果要原地修改,用双指针手动扫:一个读位置
read,一个写位置write,用unordered_set辅助判重 - 返回新长度,而不是试图“缩容”C 数组(它不能缩)
关键提醒:C 风格数组本身不管理内存,所有去重操作本质都是“覆盖+返回新长度”,别幻想它能自动变短。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










