std::set或std::unordered_set去重最直接:前者自动排序去重,后者需自定义哈希/比较函数处理const char*,且配合vector可保持插入顺序;std::sort+std::unique适用于可排序且不需原序场景。

用 std::set 或 std::unordered_set 去重最直接
如果你的字符串数组是 std::vector<:string></:string> 或 C 风格的 char* 数组,且不关心原始顺序,std::set 是最稳妥的选择——它自动排序并去重;若需保持插入顺序或追求更快平均性能,改用 std::unordered_set。
注意:C 风格字符串(如 const char*)不能直接塞进 std::unordered_set,因为默认哈希和比较基于指针值而非内容,会导致多个相同字符串被当作不同元素。必须显式提供哈希和相等函数:
struct StringHash {
size_t operator()(const char* s) const { return std::hash<:string>()(s); }
};
struct StringEqual {
bool operator()(const char* a, const char* b) const { return std::strcmp(a, b) == 0; }
};
std::unordered_set<const char stringhash stringequal> seen;
</const></:string>
- 对
std::string直接用std::unordered_set<:string></:string>即可,无需自定义 -
std::set对const char*同样不安全——它按指针地址比较,不是字典序 - 如果原数组很大,
std::unordered_set的内存开销略高,但平均O(1)查找更实用
保留原始顺序时用 std::vector + std::unordered_set 扫描
去重同时保持首次出现的位置,不能只靠容器自动处理,得手动遍历+记录已见项。
典型写法是边扫边判断、边存结果:
std::vector<:string> input = {"a", "b", "a", "c"};
std::unordered_set<:string> seen;
std::vector<:string> unique;
<p>for (const auto& s : input) {
if (seen.insert(s).second) { // insert 返回 pair<iter bool>,second 为 true 表示新插入
unique.push_back(s);
}
}
</iter></p></:string></:string></:string>
-
seen.insert(s).second比先count()再insert()少一次查找,更高效 - 若输入是
const char*数组,仍需前述自定义哈希/比较,否则行为未定义 - 不要用
std::find(unique.begin(), unique.end(), s) == unique.end()判断——那是O(n²),大数据量明显卡顿
用 std::sort + std::unique 适合只读或可排序场景
这是标准库中“原地去重”的经典组合,但要求能排序,且会打乱原始顺序。适用于你本来就要排序、或后续不再依赖顺序的情况。
对 std::vector<:string></:string> 可直接用:
std::vector<:string> v = {"c", "a", "b", "a"};
std::sort(v.begin(), v.end());
auto last = std::unique(v.begin(), v.end());
v.erase(last, v.end()); // 此时 v = {"a", "b", "c"}
</:string>
-
std::unique不真正删除元素,只是把重复项移到末尾,并返回新逻辑结尾迭代器 - 对 C 风格字符串数组(如
const char* arr[]),需配合自定义比较器:std::sort(arr, arr + n, [](auto a, auto b) { return std::strcmp(a, b) - 如果原数据量小(std::unique 配合手写线性去重可能比哈希还快——缓存友好
避免 std::map 或 std::multiset 误用
有人想用 std::map<:string int></:string> 记频次再提取 key,或者用 std::multiset 再转回 vector——这纯属绕路。前者多存了无用计数,后者没解决重复问题(multiset 允许重复)。
-
std::map和std::set底层都是红黑树,插入O(log n),而std::unordered_set平均O(1),除非你明确需要排序结果,否则别选前者 - 别对每个字符串调用
.c_str()后塞进std::unordered_set<const char></const>——临时c_str()指针生命周期只到语句结束,后续访问是悬垂指针 - 如果字符串来自
std::string_view,确保其引用的数据在整个去重过程里有效,否则std::unordered_set<:string_view></:string_view>也会出错
真正麻烦的从来不是“怎么写”,而是字符串的生存期和比较语义——const char* 的哈希陷阱、std::string_view 的生命周期、大小写敏感与否,这些细节一旦忽略,去重结果就不可靠。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











