C++ std::unique函数去重失效原因 _ 必须先sort排序详解【干货】

老伟大大_4085

老伟大大_4085

2026-04-12

565人浏览

原创

std::unique对{1,2,1,2}无反应是因为它仅比较相邻元素,而该序列中无相邻相等元素;其设计本就不适用于无序数据去重,需配合sort和erase使用。

c++ std::unique函数去重失效原因 _ 必须先sort排序详解【干货】

std::unique 为什么对 {1,2,1,2} 完全没反应

因为 std::unique 只比较相邻元素:它从第二个元素开始,逐个判断 *it == *(it-1) 是否成立。若不成立,就保留;若成立,就跳过(标记为待移除)。{1,2,1,2} 中没有任何一对相邻元素相等,所以 std::unique 直接返回原 end() 迭代器,容器内容看起来“完全没变”。

这不是 bug,是设计如此——它本就不是为无序数据准备的去重工具。

  • 常见错误现象:调用后打印整个 vector,发现重复值还在,甚至末尾出现脏数据(如 {1,2,1,2,2} → 实际变成 {1,2,1,2,2},但逻辑尾仍是 end())
  • 别试“手动把相同值挪到一起”这种土办法,效率低还易错;排序是标准、可控、可复用的前置手段
  • 若原始顺序必须保留(比如日志时间序列),std::unique 就不该用,换 std::unordered_set 配合遍历

std::sort + std::unique + erase 缺一不可

三步各自干的事不能混:std::sort 聚类,std::unique 标记,erase 物理删。漏掉任何一步,结果都不可靠。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • std::sort 后未调 std::unique:数据有序但仍有重复
  • 只调 std::unique 不 erase:容器 size() 不变,末尾残留旧值;用 for (auto x : v) 会遍历到这些“幽灵元素”
  • 用错 erase 范围,比如写成 v.erase(v.begin() + 1, v.end()):删掉的是位置而非逻辑尾,必然误删
  • 正确写法只有一种惯用模式:v.erase(std::unique(v.begin(), v.end()), v.end())

自定义类型去重时 operator== 和 sort 比较逻辑必须一致

比如按 id 去重,std::sort 用 operator 或 lambda 比较 id,std::unique 就得用对应谓词判断 id == id。两者语义错位,结果就不可预测。

  • 编译失败常见于:自定义结构体没定义 operator==,又没传谓词,std::unique 找不到比较方式
  • 运行时出错常见于:谓词写成 a.id > b.id 或 abs(a) ,和 sort 的 不匹配
  • 浮点数慎用谓词:近似相等不满足传递性,std::unique 可能跳过本该合并的项
  • 安全做法:基础类型直接用默认行为;自定义类型显式重载 operator== 和 operator,且确保逻辑同源

std::list::unique 成员函数是个例外

std::list 提供了成员函数 unique(),它自动完成“相邻去重 + 内存擦除”,不需要手配 erase。但它依然要求元素已相邻重复——也就是说,你还是得先 sort(或用 list::sort)。

  • 不能省略排序:对未排序 list 直接调 l.unique(),效果和 vector 上的 std::unique 一样——只去连续段
  • 成员函数不接受谓词重载(C++11 起支持),但用法仍是 l.unique([](const auto& a, const auto& b) { return a.id == b.id; })
  • 别在 vector 上幻想有类似捷径:没有 vector::unique,硬写等于自己实现一遍移动逻辑

最常被忽略的其实是“std::unique 返回的是迭代器,不是新容器”这件事。很多人以为它像 Python 的 set() 一样生成结果,结果在调试器里看到 size 没变、末尾数据乱码,才意识到自己漏了 erase。记住:它只负责“划界”,擦不擦,得你动手。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
sort排序函数用法
sort排序函数用法

sort排序函数的用法:1、对列表进行排序,默认情况下,sort函数按升序排序,因此最终输出的结果是按从小到大的顺序排列的;2、对元组进行排序,默认情况下,sort函数按元素的大小进行排序,因此最终输出的结果是按从小到大的顺序排列的;3、对字典进行排序,由于字典是无序的,因此排序后的结果仍然是原来的字典,使用一个lambda表达式作为key参数的值,用于指定排序的依据。

2023.09.04

1138

7

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

2023.09.20

2298

7

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

2025.06.09

4974

18

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

2025.07.04

5131

25

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.15

1051

5

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

2025.11.08

345

7

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

2026.01.05

574

7

C++ Lambda 表达式与函数式编程
C++ Lambda 表达式与函数式编程

深入讲解 C++ Lambda 表达式与函数式编程范式,涵盖 Lambda 基础语法与返回值推导、值捕获与引用捕获的区别与陷阱、初始化捕获(C++14 广义捕获)、泛型 Lambda(auto 参数)、mutable 关键字修改捕获变量、std::function 类型擦除与函数包装、std::bind 参数绑定(及其被 Lambda 替代的趋势)、Lambda 在 STL 算法(sort/transform/for_each/remo

2026.05.06

729

22

Java 函数式接口与 Lambda 进阶技巧
Java 函数式接口与 Lambda 进阶技巧

在 Java Stream 基础之上进一步深入函数式编程,涵盖 @FunctionalInterface 注解与自定义函数式接口设计、四种方法引用(静态/实例/对象/构造器)的使用场景、Lambda 中的 effectively final 变量捕获规则、函数组合(andThen/compose)与柯里化技巧、Comparator 链式比较器构建、CompletableFuture 异步函数式编排、Reactor / RxJava 响应

2026.05.08

428

28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习