c++中如何删除数组中的重复元素_c++数组去重实现

首选 std::unordered_set 辅助去重以获得无重复副本,时间复杂度低且代码简洁;原地去重则用双指针法,O(n) 时间、O(1) 空间,需手动 resize。

std::setstd::unordered_set 辅助去重(适合原始数组不可变)

如果只是需要一份无重复的副本,且不关心原数组顺序是否保留,最稳妥的做法是借助标准容器自动去重。注意:std::set 会排序,std::unordered_set 保持插入顺序但需类型支持哈希。

  • int 数组,std::unordered_set 是首选:插入快、查重快、不改变逻辑顺序
  • 若原数组很大,反复调用 insert() 后再转回 vector,比手写双指针更易读、不易出错
  • 不能直接用于 C 风格数组(如 int arr[10]),必须先知道长度,或改用 std::vector
std::vector nums = {1, 2, 2, 3, 3, 4};
std::unordered_set seen;
std::vector unique;
for (int x : nums) {
    if (seen.insert(x).second) { // insert 返回 pair,second 为 true 表示新插入
        unique.push_back(x);
    }
}

原地去重:用双指针法处理 std::vector

这是最常用也最高效的原地去重方式,时间复杂度 O(n),空间 O(1),但要求元素可比较(如 ==),且只保留首次出现的元素。

  • 适用于已排序数组时效果最佳;未排序时也能用,但结果顺序不变,重复项被“挤掉”,末尾留垃圾值
  • 返回的是新逻辑长度,必须手动调用 resize() 才真正缩短容器
  • 别直接对裸数组(如 int arr[10])用双指针——没 size 信息,容易越界
std::vector v = {1, 2, 2, 3, 2, 4};
if (v.empty()) return;
size_t i = 0;
for (size_t j = 1; j < v.size(); ++j) {
    if (v[j] != v[i]) {
        v[++i] = v[j];
    }
}
v.resize(i + 1); // 关键:不 resize 就只是前 i+1 个有效

std::unique + erase 组合(仅适用于已排序数组)

std::unique 不是真的删除元素,它把重复项移到末尾并返回新尾迭代器。必须配合 erase 才算完成去重,而且只对相邻重复有效 —— 换句话说,数组必须先排序。

  • 误用场景:对未排序数组直接调 unique,只会删掉“连着出现”的重复,比如 {1,2,1} 变成 {1,2,1}(没变),因为两个 1 不相邻
  • 排序成本不可忽略:O(n log n),比双指针 O(n) 慢,除非你本来就要排序
  • std::vector 安全;对裸数组要用 std::unique(arr, arr + n),小心传错长度
std::vector v = {3, 1, 2, 1, 3, 2};
std::sort(v.begin(), v.end()); // 必须先排
auto last = std::unique(v.begin(), v.end());
v.erase(last, v.end());

处理 C 风格数组时的常见陷阱

很多人卡在“怎么对 int arr[10] 去重”,根本问题是:C 数组没有长度元信息,函数无法知道边界,传参必须显式带长度,且无法安全缩容。

  • 不能用 sizeof(arr)/sizeof(*arr) 在函数内求长度 —— 数组退化为指针后该表达式失效
  • 所谓“删除”只能是:把唯一元素前移,返回新有效长度,调用方负责用该长度访问
  • 如果真要缩容,必须换用 std::vector 或动态分配新内存 + memcpy,别试图

    realloc
    栈数组
// 正确传参方式
int removeDuplicates(int arr[], int n) {
    if (n == 0) return 0;
    int i = 0;
    for (int j = 1; j < n; ++j) {
        if (arr[j] != arr[i]) {
            arr[++i] = arr[j];
        }
    }
    return i + 1; // 新长度
}
// 调用方需记录返回值:int new_len = removeDuplicates(arr, 10);
裸数组去重没有银弹,关键在分清“要不要改原数组”“数组是否已排序”“能不能换容器”。用错 std::unique 或忽略 resize 是高频失误点。