• C++
  • unique到底是干嘛的

  • @ 2025-2-23 19:44:17

在 C++ STL 中,std::unique 是一个用于移除相邻重复元素的算法。它不会直接删除容器中的元素,而是通过覆盖重复元素的方式将不重复的元素移动到容器前部,并返回新的逻辑结尾的迭代器。以下是它的核心用法和注意事项:


函数原型

template< class ForwardIt >
ForwardIt unique( ForwardIt first, ForwardIt last );

template< class ForwardIt, class BinaryPredicate >
ForwardIt unique( ForwardIt first, ForwardIt last, BinaryPredicate p );
  • 参数
    • first, last:需要处理的元素范围(前闭后开区间)。
    • p:自定义的二元谓词(判断两个元素是否“相等”)。
  • 返回值:指向处理后范围新结尾的迭代器。

核心行为

  1. 移除相邻重复:仅处理相邻的重复元素。
  2. 不改变容器大小:返回的新迭代器标记新结尾,但容器物理大小不变。
  3. 需要配合 erase:通常与容器的 erase 方法结合使用以实际删除元素。

基本用法示例

示例 1:去除非相邻重复(需先排序)

#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 2, 3, 2, 4, 4, 5};
    
    // 1. 先排序(去除非相邻重复)
    std::sort(vec.begin(), vec.end());
    
    // 2. 移除相邻重复元素
    auto new_end = std::unique(vec.begin(), vec.end());
    
    // 3. 实际删除尾部多余元素
    vec.erase(new_end, vec.end());
    
    // 输出结果:1 2 3 4 5
    for (int num : vec) std::cout << num << " ";
}

示例 2:自定义去重条件

struct Person {
    std::string name;
    int age;
};

int main() {
    std::vector<Person> people = {
        {"Alice", 25}, {"Bob", 30}, {"Alice", 25}, {"Charlie", 35}
    };
    
    // 自定义谓词:按 name 去重
    auto new_end = std::unique(people.begin(), people.end(),
        [](const Person& a, const Person& b) {
            return a.name == b.name;
        });
    
    people.erase(new_end, people.end());
    
    // 结果保留第一个 Alice、Bob、Charlie
}

注意事项

场景 处理方式
非排序容器去重 先调用 std::sort,否则只能去除相邻重复
保留最后一个重复项 结合 std::reverse 反向处理(见下方代码)
自定义类型去重 必须提供正确的谓词(如比较结构体的某个字段)
字符串去重 直接应用即可(例如去除连续重复字符)

保留最后一个重复项(反向去重)

std::vector<int> vec = {1, 2, 2, 3, 2, 4, 4, 5};
std::sort(vec.begin(), vec.end()); // 排序
std::reverse(vec.begin(), vec.end()); // 反转

auto new_end = std::unique(vec.begin(), vec.end());
vec.erase(new_end, vec.end());
std::reverse(vec.begin(), vec.end()); // 反转回来

// 结果:1, 2, 3, 4, 5 → 若原数据未排序可能保留不同元素

性能分析

  • 时间复杂度:(O(n)),遍历一次容器。
  • 适用场景
    • 需要保留唯一元素但顺序敏感(如日志去重)。
    • 配合排序实现全局去重(时间复杂度 (O(n \log n)))。

总结

std::unique 的正确使用流程:

  1. 排序(若需全局去重)。
  2. 调用 std::unique 获取新结尾。
  3. 使用 erase 删除尾部冗余元素。

0 条评论

目前还没有评论...