C++如何快速删除Vector中的重复元素?(一行代码)

2次阅读

std::unique配合erase仅适用于已排序vector的一行去重,它移动重复元素至末尾再删除;未排序时需先sort,保留原序则须用unordered_set+remove_if。

C++如何快速删除Vector中的重复元素?(一行代码)

std::unique + erase 组合是唯一靠谱的一行解法

不是所有“去重”都能靠一行解决,但对已排序的 std::vectorstd::unique 配合 erase 确实能压缩成一行。它不真正删除元素,只是把重复项移到末尾,再靠 erase 删掉那段“脏尾巴”。没排序就直接用?结果不可预测——std::unique 只删相邻重复项。

  • 必须先调用 std::sort(如果允许改变顺序),或用 std::stable_sort(保留首次出现位置)
  • std::unique 返回的是新逻辑结尾的迭代器,不是容器大小,漏接这个返回值会导致 erase 删错范围
  • 原地操作,无额外空间开销,时间复杂度 O(n log n)(主要花在排序上)

示例:

std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6, 5};<br>std::sort(v.begin(), v.end());<br>v.erase(std::unique(v.begin(), v.end()), v.end()); // 这一行完成去重

想保留原始顺序?别硬套 std::unique,得换思路

原始顺序很重要时,std::unique 直接失效——它只认相邻重复。这时候“一行代码”基本是个幻觉,但可以压成极简两步:用 std::unordered_set 记录见过的值,配合 std::remove_if + erase

  • 不能用 std::set(慢),必须用 std::unordered_set,否则去重本身变成 O(n²)
  • std::remove_if 不真删,只是重排;必须紧跟 erase 才生效,少一个就白干
  • 注意 unordered_set::insert 返回 pair<iterator bool></iterator>,只看 .second 就能判断是否首次插入

示例:

std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6, 5};<br>std::unordered_set<int> seen;<br>v.erase(std::remove_if(v.begin(), v.end(), [&seen](int x) { return !seen.insert(x).second; }), v.end());

立即学习C++免费学习笔记(深入)”;

std::unique 报错 “invalid operator==”?检查你的元素类型

自定义结构体或类用 std::unique 时崩了,大概率是没提供可比性支持。它内部依赖 operator== 判断相等,不是靠地址也不是靠 memcmp。

  • 如果是 Struct,必须显式定义 bool operator==(const MyStruct& other) const
  • std::unique 的第三个参数传自定义谓词?可以,但务必确保谓词满足等价关系(自反、对称、传递),否则行为未定义
  • 指针成员的类慎用默认比较——比较的是指针值,不是所指内容

性能陷阱:小数据量别迷信“一行”,手动遍历反而更稳

向量只有几十个元素?用 std::uniqueunordered_set 可能比手写双循环还慢。哈希表建表、内存分配、缓存不友好,全在拖后腿。

  • 元素少于 ~50 个时,用 for 嵌套 + std::find 判断是否已存在,代码清晰且实际更快
  • std::unique 要求随机访问迭代器,但如果你用的是 std::list,就得切到 unique() 成员函数——别混用
  • 编译器对 std::unique + erase 组合优化有限,别指望它自动向量化

事情说清了就结束。

text=ZqhQzanResources