用 std::unordered_map 统计频次是最直接的做法:遍历数组将元素作 key、次数作 value 存入,平均时间复杂度 o(n),空间 o(n);优于 std::map(o(log n));需注意空数组、全等频次等边界情况。

用 std::unordered_map 统计频次是最直接的做法
核心思路就是遍历一次数组,把每个元素当作 key,出现次数当作 value 存进哈希表。C++ 标准库的 std::unordered_map 平均插入和查找都是 O(1),整体时间复杂度 O(n),空间 O(n) —— 对绝大多数场景足够快且清晰。
注意别手误写成 std::map:它底层是红黑树,插入是 O(log n),没这个必要;除非你后续还要按 key 排序,否则纯统计频次时 unordered_map 更合适。
示例片段:
std::vector<int> arr = {1, 3, 2, 3, 4, 3, 2};
std::unordered_map<int int> count;
for (int x : arr) count[x]++;
int mode = arr[0];
for (const auto& p : count) {
if (p.second > count[mode]) mode = p.first;
}
// mode 就是出现最多的元素(有多个最大值时取最后一个遇到的)
</int></int>
遇到重复最大频次时怎么选?std::max_element + lambda 更可控
上面的手动遍历逻辑在多个元素并列最高频次时,行为取决于遍历顺序(unordered_map 无序),结果不可预测。如果业务要求“取第一次出现的”或“取最小/最大值”,就得显式控制。
更稳妥的方式是用 std::max_element 配合自定义比较,或者先找出最大频次,再扫一遍原数组找第一个达到该频次的元素。
- 要“首次出现的众数”:先算出 max_count,再遍历原数组,对每个
x查count[x]是否等于 max_count,一找到就返回 - 要“值最小的众数”:遍历
count时,用p.first 做第二层判断 - 别在循环里反复调用
count.size()或count.max_size()——这些不是 O(1),纯属干扰
数组元素范围小且已知时,用 vector 替代 map 更快
比如题目限定是「0 到 999 的整数」,或「字符(0–255)」,那就完全没必要用哈希表。直接开一个 std::vector<int></int> 当计数桶,下标即元素值,访问是真·O(1),没有哈希冲突、没有内存分配开销,cache 友好得多。
示例(假设元素是 unsigned char):
std::vector<int> bucket(256, 0); for (unsigned char c : arr) bucket[c]++; int mode = 0; for (int i = 1; i bucket[mode]) mode = i; } </int>
注意:如果元素可能为负,或范围极大(如 int 全域),这种桶排思路就失效了,硬开数组会炸内存或越界。
用 std::nth_element 能不能绕过哈希?不能,别试
有人想“排序后取中位数附近连续段”,或者用 nth_element 找第 k 大——这是误解。众数不依赖顺序,只依赖频次。对数组本身排序无法暴露频次信息,除非你先去重+计数,那又绕回 map 或桶了。
还有一种错误尝试:对数组做 unique 后统计相邻重复段长度。这仅在「相同元素连续出现」时才有效(比如输入已排序),但题干没这个前提,std::unique 会漏掉分散的重复项。
结论很明确:只要没额外约束(如已排序、范围极小、内存极度受限),unordered_map 是最平衡、最不易出错的选择。
真正容易被忽略的是边界:空数组没众数,单元素数组直接返回;还有当所有元素频次相同时,你得确认需求到底要“任意一个”还是“全部”——代码里不会自动帮你做这个判断。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











