std::set可一步完成去重+排序,自动升序且去重,适用于可比较类型;需注意构造后拷贝回原容器,C风格数组可用迭代器区间构造。

用 std::set 一步完成去重+排序最省事
如果原始数组允许丢弃顺序、不介意额外空间,std::set 是最直接的选择:它自动去重且内部按升序维护。注意它只接受可比较类型(如 int、double、自定义类型需重载 operator<)。
实操建议:
- 把原数组元素插入
std::set<int>,再拷贝回容器(如std::vector)或遍历输出 - 别用
std::unordered_set—— 它去重但不排序,还得额外调std::sort - 若原数组是 C 风格数组(如
int arr[10]),用std::set<int>(arr, arr + 10)构造即可
int arr[] = {3, 1, 4, 1, 5, 9, 2, 6, 5};
std::set<int> s(arr, arr + 9);
// s 现在含 {1,2,3,4,5,6,9},已去重且升序
原地去重+排序(保留数组,用 std::sort + std::unique)
这是标准库推荐做法,适合需要复用原数组内存、或必须返回 int* / std::array 的场景。关键点:先排序再 std::unique,因为 std::unique 只移除**相邻重复项**。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 先
std::unique再std::sort→ 去重失败(重复元素可能不相邻) - 忽略
std::unique返回的迭代器,直接用原size遍历 → 访问到“逻辑删除”的脏数据 - 对
std::vector用erase(unique(...))后没 shrink_to_fit → 内存未释放
std::vector<int> v = {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()); // 真实删除冗余元素
// v 现在是 {1,2,3,4,5,6,9}
处理自定义结构体:必须提供严格弱序比较
若数组元素是结构体(如 struct Point { int x, y; };),std::sort 和 std::set 都会编译失败,除非你明确定义比较逻辑。
使用场景:
- 按
x升序,x相同时按y升序 → 重载operator<或传 lambda 给std::sort - 去重依据是整个结构体值相等 → 还需定义
operator==(std::unique依赖它) - 避免用
memcmp或裸指针比较 —— 未定义行为,尤其含 padding 字段时
struct Point {
int x, y;
bool operator<(const Point& p) const {
return x != p.x ? x < p.x : y < p.y;
}
bool operator==(const Point& p) const {
return x == p.x && y == p.y;
}
};
std::vector<Point> pts = {{1,2}, {3,4}, {1,2}};
std::sort(pts.begin(), pts.end());
pts.erase(std::unique(pts.begin(), pts.end()), pts.end());
性能与边界注意点
小数组(std::set 插入是 O(n log n),但常数较大;std::sort+std::unique 是 O(n log n) 排序 + O(n) 去重,缓存友好性更好。
容易被忽略的地方:
-
std::unique不改变容器大小,只是把重复元素移到末尾 —— 必须配合erase才真正缩短 - 对
std::array不能直接erase,得用迭代器范围构造新std::array或改用std::vector - 浮点数去重要小心精度:直接用
==比较可能失效,应改用std::abs(a - b) < eps自定义谓词


















