原序去重应使用std::unordered_set辅助遍历:遍历时查重并首次出现即加入结果vector,确保顺序不变;不可用std::set(排序破坏顺序)或std::unique(仅去相邻重复且需先排序)。

用 std::unordered_set 辅助遍历去重最直接
原序去重本质是「保留第一次出现的元素,跳过后续重复项」,std::unordered_set 提供 O(1) 平均查找,适合边遍历边记录已见元素。注意它不保证插入顺序,但这里只用作查重容器,不影响输出顺序。
实操建议:
- 遍历原数组,对每个元素先查
seen.find(x) == seen.end(),成立则加入结果容器并插入seen - 结果存入
std::vector(非原地修改数组,避免越界或逻辑混乱) - 输入为
int等内置类型时,unordered_set无需额外哈希特化;若为自定义类型,需提供hash和operator== - 不要用
std::set替代——它按值排序,会破坏原序
原地去重只能用于已排序数组,不适用于本需求
std::unique 是 C++ 标准库中唯一标称“去重”的算法,但它要求输入已严格升序/降序,且仅移除**相邻重复项**。对 {1,2,1} 这类乱序数组,std::unique 不起作用——它只会检查 1,2(不重复)、2,1(不重复),最终返回原数组。
常见错误现象:
- 直接对未排序数组调用
std::unique+erase,结果和原数组完全一样 - 先
sort再unique,虽能去重但彻底打乱原始位置关系,违背“按原顺序”要求 -
std::unique返回的是新逻辑尾迭代器,必须配合erase才真正缩容,漏掉这步会导致访问越界
处理 C 风格数组时注意生命周期和大小传递
C++ 中所谓“C 风格数组”(如 int arr[] = {1,2,1,3};)不是对象,无法直接传入模板函数获取长度。若你拿到的是裸指针+长度,操作逻辑和 vector 一致;若只有指针(如函数参数 int* arr),必须额外传入 size_t n。
示例片段:
int arr[] = {1, 2, 1, 3, 2};
size_t n = sizeof(arr) / sizeof(arr[0]);
std::unordered_set<int> seen;
std::vector<int> result;
for (size_t i = 0; i <h3>重复元素类型影响哈希与比较行为</h3>
<p>如果数组元素是 <code>std::string</code>、<code>std::pair<int></int></code> 或自定义结构体,<code>unordered_set</code> 默认可能无法编译——因为标准库没为它们提供通用哈希特化。</p>
<p>解决路径:</p>
<ul>
<li>
<code>std::string</code>:C++11 起已内置特化,可直接用</li>
<li>
<code>std::pair</code>:需手动写哈希函数,或改用 <code>std::set<:pair>></:pair></code>(牺牲 O(1) 查找换稳定性,且仍不破坏原序)</li>
<li>自定义类:必须定义 <code>operator==</code> 和一个兼容的 <code>std::hash</code> 特化,否则编译失败</li>
<li>若只是临时去重且数据量小,用 <code>std::find(result.begin(), result.end(), x) == result.end()</code> 线性查找更省事,避免哈希配置麻烦</li>
</ul>
<p>原序去重真正的复杂点不在算法,而在明确「数组形态」和「元素类型」——裸数组要自己管长度,模板容器得看迭代器范围,而自定义类型几乎必然要补哈希逻辑。别被 <code>unique</code> 的名字带偏,它和“保持原序”是互斥的。</p></int></int>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











