词频统计TopN+单机+内存限制+java

本文介绍了一道关于统计1M文件中频数最高的50个词的题目,采用文件分片、内存限制100KB的策略。通过HashMap统计子文件词频,维护一个50节点的最小堆,实现词频统计。文章讨论了文件切分、内存计算、最小堆实现以及代码实现,最后反思了单机内存限制下的优化问题。

前言

  前几天,同学问了我一道笔试题,网上大部分只有思路,良莠不齐。并且没找到java代码来实现的~所以就动手敲了一份,尽可能在思路上做到全面,也欢迎大家指教。代码地址

题目

  有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的50个词。
  为了本机测试方便,将题目改成
  有一个1M大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是100KB。返回频数最高的50个词。

思路

  毕竟是经典题目,大体思路如下:

  1. 文件分片,使得子文件不超过内存限制大小。
  2. 通过hashMap统计每个子文件中出现词的频率。
  3. 维护一个含有50结点的最小堆,将hashMap的值依次与堆顶(最小值)作比较。如果大于堆顶值,则替换堆顶值,并重新调整最小堆。所有子文件遍历完,最小堆中剩下的节点就是频数最高的50个单词。

  写代码前,还要多向自己提问,这样才能让思路尽可能全面些:

  • Q:怎样切分文件,尽可能平均且方便?
  • A:参照HashMap分桶原理(当然redis等的切片也类似),将 word的hash值 & 切分文件数量;这样可以防止hashCode为负的情况,为了切片更均匀,切分文件的数量要为2^n 。
//HashMap分桶源码
 if ((p = tab[i = (n - 1) & hash]) == null)
   tab[i] = newNode(hash, key, value, null);
 else {
   
   ...}
  • Q:怎样确定切分文件的数量?
  • A:当然要通过待切分文件的大小,和实际内存大小计算得出。然后再取最接近该结果的2^n,这里也可以参考HashMap获取初始容量的算法。
    /**
     * HashMap源码:获取初始容量的方法 → 找到最接近设置值的2^n
     * Returns a power of two size for the given target capacity.
     */
    static final int tableSizeFor(int cap) {
   
   
        int n = cap - 1;	//-1防止本身cap就是2的指数
        n |= n >>> 1;		//n=n|(n>>>1)
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
  • Q:最小堆一般是基于数组来维护的,怎样同时存放word和count?
  • A:通过ArrayList来维护最小堆,里面存放wordCount的实体类。

项目结构

在这里插入图片描述
红框内,从上至下:

  • domain/WordCount → 实体类;
  • FileUtils → File操作类,包含文件分片、生成符合题目要求的文件等方法;
  • MinHeapArray → 基于数组维护的最小堆,对本项目无用,作为思路参考;
  • MinHeapList → 基于ArrayList维护的最小堆;
  • WordCountMain → 主运行文件,入口;

代码

  多说无益,上代码:

  1. 先要生成符合题目要求的文件,用于测试:
    /**
     * 由一篇英文文章生成
     * 生成每一行是一个词的文件,每个文件不超过16个字节
     * @param srcFileName
     * @param destFileName
     * @throws IOException
     */
    public static void generateWordTxt(String srcFileName, String destFileName) throws IOException {
   
   
        BufferedReader br = new BufferedReader(
                new InputStreamReader(new FileInputStream(srcFileName)));
        StringBuffer stringBuffer = new StringBuffer();
        String line;

        while ((line = br.readLine()) != null) {
   
   
            stringBuffer.append(line);
        }

        String[] words = stringBuffer.toString().split("[^a-zA-Z]+");

        PrintWriter pw = new PrintWriter(new FileWriter(destFileName, true));
        for (String word : words) {
   
   

//          ASCII码、UTF-8、GBK 一个英文字母等于一个字节
//          Unicode、utf-16be   一个英文字母等于两个字节
内容概要:本文提出了一种融合元胞自动机邻域驱动遗传算法与关键工序定向随机重启爬山算法(GA-RRHC)的混合优化方法,用于求解高柔性柔性作业车间调度问题(FJSSP),以实现最小化最大完工时间的目标。该算法通过元胞自动机构建动态邻域结构,增强种群多样性与搜索效率,结合遗传算法的全局探索能力和随机重启爬山算法的局部精细化优化能力,并引入关键路径识别机制指导搜索方向,有效避免陷入局部最优。整个方法在Matlab平台上实现了完整的算法流程与仿真实验,验证了其在复杂调度场景下的优越性能与鲁棒性,适用于高柔性制造系统的生产调度优化需求。; 适合人群:具备一定编程基础和运筹优化背景,从事智能制造、工业工程、自动化或相关领域研究的研发人员及研究生(工作或学习年限1-3年)。; 使用场景及目标:①解决高柔性作业车间中多工序、多设备、多约束条件下的调度优化难题;②研究混合智能优化算法的设计与实现机制,特别是遗传算法与局部搜索策略的融合方式;③为实际生产系统提供高效的调度方案,缩短生产周期,提高资源利用率。; 阅读建议:此资源以Matlab代码为核心载体,强调算法实现与仿真实验的结合,建议读者在阅读过程中动手运行并调试代码,深入理解元胞邻域构造、关键路径识别及随机重启机制的作用,同时可拓展应用于其他组合优化问题。
内容概要:本文档为成都科洛威尔科技有限公司生产的MIL-1394B仿真板卡的API函数使用手册,详细介绍了该板卡在Windows和Linux环境下进行MIL-1394B/AS5643总线协议仿真和测试所需的API函数、数据结构、使用流程及例程。板卡支持CC(控制计算机)、RN(远程节点)和BM(总线监控)三种工作模式,提供丰富的函数用于设备管理、节点控制、消息收发、故障注入、中断处理等功能,并涵盖数据包格式、发送接收流程、错误检测机制等关键技术细节。手册还提供了函数调用示例和典型应用场景,帮助开发者快速掌握板卡的开发与调试。; 适合人群:从事航空电子、嵌入式系统或工业自动化领域,具备C/C++编程基础并熟悉总线通信协议的1-3年工作经验的软硬件研发工程师。; 使用场景及目标:①在复杂总线环境中实现高精度数据仿真与测试;②开发基于MIL-1394B协议的通信系统;③进行消息收发控制、时序偏移管理、错误注入测试及中断响应处理等高级功能验证;④通过API调用实现对板卡工作模式、数据流、状态监测的全面控制。; 阅读建议:建议结合配套的demo示例程序进行实践,重点理解各函数的调用时序与参数配置逻辑,尤其关注STOF时序控制、消息发送模式、错误注入机制等核心功能的实现原理。使用前需仔细阅读“基本使用流程”与“附录”部分,确保正确配置硬件环境与通信参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值