最常用高效方式是hashmap统计频次后用最小堆或排序取top-k:先遍历数据用map.merge或compute更新频次,再用priorityqueue(o(n log k))或stream.sorted(o(m log m))获取前k项。

直接用 HashMap 统计频次,再结合优先队列(最小堆)或排序取前 K,是最常用且高效的方式。关键不在 HashMap 本身,而在“统计后如何高效选出 Top-K”。
用 HashMap 统计频次
这是第一步,也是最轻量的一步:遍历数据,以元素为 key、出现次数为 value 累加。
- 字符串、数字、自定义对象(需正确重写 hashCode() 和 equals())都可作为 key
- 推荐使用 Map
,更新时用 map.merge(item, 1, Integer::sum)或map.compute(item, (k,v) -> v == null ? 1 : v + 1),线程不安全但快 - 如果数据来自文件/流/数据库,边读边 put,避免全量加载到内存
用最小堆(PriorityQueue)找 Top-K
当 K 远小于总不同元素数(比如 10 万种元素里取前 10),堆比全排序更省内存、更快(时间复杂度 O(N log K))。
- 定义最小堆:
PriorityQueue<map.entry integer>> heap = new PriorityQueue((a, b) -> a.getValue() - b.getValue());</map.entry> - 遍历 HashMap 的 entrySet(),每次插入堆;若堆大小超过 K,就 poll 掉最小频次项
- 最后堆中剩下的就是频次最高的 K 个(注意:堆顶是最小的,所以结果需倒序输出)
用 Stream + sorted 取前 K(适合中小规模)
代码简洁,适合 K 不大、不同元素总数可控(比如 ≤ 10 万)的场景。
list = map.entrySet().stream()<br> .sorted(Map.Entry.<t integer>comparingByValue().reversed())<br> .limit(K)<br> .collect(Collectors.toList());</t>
- 注意:sorted 是全排序,时间复杂度 O(M log M),M 是不同元素个数;大数据量时慎用
- 如需稳定顺序(同频次按插入/字典序排),可在 sorted 后加 thenComparing
进阶建议:内存与性能兼顾
面对真正“大量数据”(如上亿条日志),单机 HashMap 可能爆内存,这时要考虑:
- 预过滤:先用布隆过滤器或采样快速排除低频项
- 分片聚合:多线程分段统计(每个线程用局部 HashMap),最后 merge 合并
- 外部排序/Spark:超大规模时交给分布式框架,HashMap 只做单机阶段的汇总单元
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











