用std::unordered_map统计频次后,根据n大小选择partial_sort、nth_element或堆优化提取前n高频元素,注意自定义类型哈希、去重及排序稳定性。

用 std::unordered_map 统计频次是最直接的起点
想找出出现最多的前 N 个元素,第一步永远是知道每个元素出现了几次。C++ 里最自然的选择是 std::unordered_map<t int></t>,它平均 O(1) 插入和查找,比 std::map 的 O(log n) 更适合纯计数场景。
注意别用 std::map 代替——除非你同时需要按键排序,否则只是徒增开销。另外,如果数组元素类型是自定义类,得确保已定义 operator== 和哈希函数(或传入自定义哈希),否则编译会报错:error: call to implicitly-deleted default constructor of 'std::hash<mytype>'</mytype>。
示例片段:
std::unordered_map<int int> count; for (int x : arr) count[x]++;</int>
用 std::partial_sort 或 std::nth_element 提取前 N 个高频项
统计完频次后,你手上是一个键值对集合,但不需要全排序——只要前 N 个。这时 std::partial_sort 比 std::sort 更省:它保证前 N 个有序,其余部分不保证顺序,时间复杂度约 O(k log k),k 是 map 大小;而 std::nth_element 更快(O(k) 平均),但它只保证第 N 个位置正确,前 N 个内部无序,需额外处理。
常见错误是把 map 直接丢给 sort——不行,map 不支持随机访问迭代器。必须先转成 vector<pair int>></pair>。
- 要结果按频次降序、频次相同时按值升序?用
partial_sort+ 自定义比较 lambda - 只关心“哪些元素在前 N”,不care它们之间顺序?
nth_element更快,但记得再用sort对前 N 个单独排 - N 接近 map.size()?那直接
sort反而更稳,避免 partial_sort 的常数开销
处理频次相同的情况:排序逻辑决定结果稳定性
当多个元素频次一样时,是否保留原始出现顺序(稳定)?标准库算法默认不稳定。如果你依赖“先出现的元素优先”,就得自己记录首次索引,或者改用 std::stable_sort(但代价是 O(k log k) 时间且不能用 partial_sort)。
更实际的做法是明确业务需求:
- 频次相同就按元素值排序(如数字从小到大)——加一行
a.second != b.second ? a.second > b.second : a.first - 频次相同就随机返回任意一个?不用额外逻辑,
nth_element就够了 - 需要严格按原数组中第一次出现位置排序?得预扫一遍建
first_occurrence映射,再参与比较
内存与性能边界:N 很小或很大时的优化取舍
如果 N 是 1 或 2(比如找众数),完全没必要建 vector 再排序。遍历 map 一次,维护一个大小为 N 的 std::priority_queue(小顶堆)更省空间:每次插入后 pop 最小频次项,最终堆里剩的就是前 N。时间 O(k log N),空间 O(N)。
反过来说,如果 N 接近去重后元素总数(比如 N = count.size()-1),堆方法反而慢,vector + partial_sort 更合适。
另外,别忽略数据局部性:如果数组极大但重复极高(比如只有几十个不同值),unordered_map 的哈希冲突可能拖慢。此时可考虑 std::vector<int></int> 直接计数(适用于值域小且连续的整数)。
真正容易被忽略的是:返回结果要不要去重?题目说“前 N 个元素”,但若原数组有重复值,结果里每个元素只应出现一次——map 统计天然满足这点;但若误用 vector 存原始元素再统计,就可能重复计入。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











