c++中如何使用std::unique去除vector重复元素_c++容器去重步骤【汇总】

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::vector 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());                                 // 真正删除重复元素

注意:std::unique 不改变容器大小,只把重复元素“挤到末尾”,并返回指向新逻辑结尾的迭代器。

用 std::set 或 std::unordered_set 做无序去重

如果不需要保持原始顺序,且元素可比较(set)或可哈希(unordered_set),直接构造集合最简洁:

std::vector v = {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::vector v = {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,要么靠预处理(比如按某字段分组后单独去重)。没意识到这点,就容易在调试时花几小时找“为什么还剩重复”。