商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > C++如何高效删除vector中重复的相邻元素 _ std::unique用法实战【实战】

C++如何高效删除vector中重复的相邻元素 _ std::unique用法实战【实战】

  发布于2026-07-08 阅读(0)

扫一扫,手机访问

直接说结论:std::unique 配合 erase 是标准、安全、高效的做法,但必须时刻记住——它只处理“相邻重复”,而且不会真的缩短容器。如果漏掉 erase 那一步,数据其实还赖在内存里,只是被覆盖了,打印出来你会怀疑人生。

C++如何高效删除vector中重复的相邻元素 _ std::unique用法实战【实战】

为什么 std::unique 不能单独删除元素

std::unique 本质上是个“搬运工”:它把重复的相邻元素往前挪,然后扔给你一个指向新逻辑末尾的迭代器。但它既不改容器大小,也不调析构函数。很多新手只写一句 std::unique(v.begin(), v.end()) 就以为万事大吉,结果 v.size() 纹丝不动,打印出来好像还有重复值——其实是旧值在末尾“诈尸”。

  • 它只比较 *(i)*(i-1),绝不会扫描全量去重
  • 输入必须已经排好序,或者至少让重复项相邻排列,否则等于白干
  • 返回的是迭代器(逻辑新终点),不是容器的新 size

正确删除相邻重复的三步写法

标准组合拳就一招:std::unique + erase + end()。这是唯一符合 RAII 和迭代器失效规则的写法,没有替代方案。

std::vector v = {1, 1, 2, 2, 2, 3, 4, 4, 5};
auto new_end = std::unique(v.begin(), v.end());
v.erase(new_end, v.end()); // 必须这一步,不能省
// v 现在是 {1, 2, 3, 4, 5}
  • 顺序不能反:先 unique 拿到新终点,再用 erase 清理尾部残留
  • 千万别用 v.resize(std::distance(v.begin(), new_end)) 代替 erase,对于自定义类型,这可能会跳过析构函数,埋下资源泄漏的隐患
  • 如果 vector 里存的是指针或智能指针,unique 比较的是指针值本身,不是所指对象的内容——这种坑踩一次就记住了

自定义比较逻辑怎么写(比如忽略大小写去重字符串)

传一个 lambda 或函数对象给 std::unique 的第三个参数,让它按你定义的“相等”来判断相邻项即可。

std::vector words = {"Apple", "apple", "Banana", "banana"};
auto new_end = std::unique(words.begin(), words.end(), 
    [](const std::string& a, const std::string& b) {
        return std::equal(a.begin(), a.end(), b.begin(), b.end(),
            [](char x, char y) { return std::tolower(x) == std::tolower(y); });
    });
words.erase(new_end, words.end());
  • lambda 必须接受两个同类型参数,返回 bool
  • 这个例子能生效的前提是大小写混排的字符串已经相邻;如果没排好序,必须先 std::sortunique
  • 性能敏感时,lambda 里尽量避免深拷贝或内存分配,参数传 const std::string& 而不是值

最容易翻车的一点:如果你的 vector 是从别的算法结果拼接来的,或者中间插入过元素,相邻性很可能已经被破坏——这时候 std::unique 不是你该用的工具,该换 std::set 或者哈希去重,但那属于“删全局重复”的范畴,跟“删相邻”是两码事。

本文转载于:https://www.php.cn/faq/2423629.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注