C++ STL 学习笔记(一):vector 去重的三种实现方法详解

C++ STL 学习笔记(一):vector 去重的三种实现方法详解

​ 在C++开发中,vector去重是最常见的数据处理需求。本文将详细介绍使用C++标准库中的sort(),unique(), erase()函数组合实现容器vector去重, 本笔记主要介绍三种实现方法:(1)基础数据类型去重;(2)自定义结构体使用sort+unique 去重;(3)使用set 去重;帮助开发者根据不同场景选择最优方案。

1.1 基础数据类型去重

unique()函数作用是去掉容器中相邻元素的重复元素,然后返回指向第一个重复元素的迭代器。unique()实质上是一个伪去除 ,它并不是真正把重复的元素删除,而是用不重复的元素把重复的元素覆盖了,所以总长度其实是不变的。

​ 因此在利用unique()函数前需要对容器内的数据排序,可以通过sort()函数实现。sort()函数的作用是对容器指定范围内的元素按指定格式进行排序,默认从小到大。在利用unique()函数后需要擦除从返回的迭代器对于的元素到最后元素的所有的元素,可以通过erase()函数实现。erase()函数的作用是擦除容器指定范围内的元素。综上所属:去除的主要思路:先用sort排序(让重复元素相邻)、再唯一(用unique 把重复元素移到容器的末尾)、最后用erase()于删除最后面的那段"重复"元素。对于

​ 对于基础类型数据(如int,float等),最简单直接的方法是使用上述的sort+unique+erase组合。下面是代码案例实现

C++ 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    vector<int> vec = {1, 2, 3, 2, 1, 4, 5, 4};
    
    cout << "去重前: ";
    for (int num : vec) cout << num << " ";
    cout << endl;

    // 排序后去重
    sort(vec.begin(), vec.end());
    vec.erase(unique(vec.begin(), vec.end()), vec.end());

    cout << "去重后: ";
    for (int num : vec) cout << num << " ";
    cout << endl;

    return 0;
}

其中注意:

  • sort()函数的头文件:#include<algorithm>
  • unique()函数的头文件:#include<iostream>
  • erase()函数的头文件:#include<vector>

1.2 自定义结构体去重

​ 另外对于容器中,如结构体、类对象等,为了实现去重操作,还可以通过对sort算法需要重载<操作符或定义比较函数,对unique算法需要重载==操作符,通过对其中的某一个成员变量进行操作来实现,然后采用sort+unique+erase。其代码实现如下

C++ 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Person {
    string name;
    int age;
    
    // 定义相等运算符
    bool operator==(const Person& other) const {
        return name == other.name && age == other.age;
    }
};

// 定义比较函数
bool comparePerson(const Person& a, const Person& b) {
    if (a.name != b.name) return a.name < b.name;
    return a.age < b.age;
}

int main() {
    vector<Person> people = {
        {"Alice", 25},
        {"Bob", 30},
        {"Alice", 25},
        {"Charlie", 35},
        {"Bob", 30}
    };

    cout << "去重前:\n";
    for (const auto& p : people) 
        cout << p.name << " (" << p.age << ")\n";

    sort(people.begin(), people.end(), comparePerson);
    people.erase(unique(people.begin(), people.end()), people.end());

    cout << "\n去重后:\n";
    for (const auto& p : people) 
        cout << p.name << " (" << p.age << ")\n";

    return 0;
}

其中关键点:

  • 必须定义operator==用于unique判断相等;

  • 代码简介,但会改变原始顺序;

  • 对于大型数据集合,利用set的集合去重更高效;

1.3 使用set进行去重

​ 对vector的去重操作还可以利用set容器的特性实现,思路比较简单,对于自定义类型,可以使用set自动去重的特性,需要定义operator<运算符。其案例代码如下

C++ 复制代码
#include <iostream>
#include <vector>
#include <set>
using namespace std;

struct Product {
    string id;
    double price;
    
    // 定义小于运算符
    bool operator<(const Product& other) const {
        if (id != other.id) return id < other.id;
        return price < other.price;
    }
};

int main() {
    vector<Product> products = {
        {"P1001", 99.99},
        {"P1002", 199.99},
        {"P1001", 99.99},
        {"P1003", 299.99},
        {"P1002", 199.99}
    };

    cout << "去重前:\n";
    for (const auto& p : products) 
        cout << p.id << " ($" << p.price << ")\n";

    // 使用set去重
    set<Product> uniqueProducts(products.begin(), products.end());
    products.assign(uniqueProducts.begin(), uniqueProducts.end());

    cout << "\n去重后:\n";
    for (const auto& p : products) 
        cout << p.id << " ($" << p.price << ")\n";

    return 0;
}

其关键点如下

  • set基于operator<自动排序和去重;

  • 代码简洁,但会改变原始顺序

  • 对于大型数据集,set方法可能更高效

方法比较

方法 适用场景 时间复杂度 代码复杂度
sort+unique 基础数据类型 O(n log n) + O(n)
自定义结构体sort+unique 需要保持顺序的自定义类型 O(n log n) + O(n)
set去重 不需要保持顺序的自定义类型 O(n log n)

参考资料

C++中vector去重的三种实现方法详解_文心快码

STL之vector去重三步曲(利用unique函数)_vector unique-CSDN博客