面试场景题:100G的文件,找出出现次数最多的IP,或对文件中的id进行排序,如何处理?

#牛客AI配图神器#

一、场景题:一个存储IP地址的100G 的文件, 找出现次数最多的 IP ?

和大文件中存id,然后要求排序问题一样的处理思路

使用MapReduce的思想解决,加上哈希分割,先将大文件中的IP地址按照哈希函数进行分割,存到多个文件上,接着每个分片单独处理,用Hashmap统计IP出现频次,记录当前分片最大值。最后归并处理,找出所有候选IP中的最大出现次数的IP。

1.哈希分割(预处理阶段)

① 使用高效哈希函数计算每个IP的哈希值② 按哈希值取模分片:hash(ip) % N → 生成N个分片文件

分片数计算:假设可用内存1G,每个分片限制为50MB → N=2000分片

2.分块统计(Map阶段)

每个分片处理时:

  • 将小文件加载到内存中
  • ① 使用HashMap<String, Long>统计IP出现频率 ② 同步维护当前分片的最大值:maxIP和maxCount

3.全局归并(Reduce阶段)

  • 读取所有中间结果文件中的最高频IP
  • 在这些候选IP中找出全局出现次数最多的IP

4.关键问题

1.哈希函数设计

file_index = hash(IP地址) % 256

这个哈希函数确保了同一个IP地址一定会被映射到同一个文件索引

2.某个分割的文件仍然过大,怎么解决?

若某分片的IP种类过多导致HashMap溢出,解决方案:

  • 对该分片进行二次哈希分片

5.面试回答模板

“我会采用分布式计算中常用的分治策略:

  1. 哈希分片:将IP按哈希值分散到256个分片中,确保相同IP在同一分片;
  2. 分块统计:对每个分片使用HashMap统计频率,同时记录分片内的最大值;
  3. 全局归并:比较所有分片的最大值得到最终结果。

二、场景题:100G的文件里有很多id,用1G内存的机器排序,怎么做?

海量数据排序思路

核心方案:外排序(分治+多路归并)MapReduce

外排序是指数据量太大,无法全部加载到内存中,需要将数据分成多个小块进行排序,然后将排序后的小块合并成一个大的有序块

1.分块排序(Map阶段)

  • 分块策略 按1G内存容量限制,将100G文件拆分为 200个500MB分块(保留内存用于排序计算和系统开销)
  • 内存排序 每个分块加载至内存后: ① 使用快速排序(时间复杂度O(n log n)) ② 去重优化:若存在重复ID,排序时合并相同项(节省存储空间),根据要求是否去重
  • 临时文件写入 排序后分块写入磁盘,命名规则:chunk_0001.sorted ~ chunk_0200.sorted

2. 多路归并(Reduce阶段)

使用K路归并算法合并这些排序好的小文件

具体实现方法:

  • 从每个小文件中读取一小部分数据到内存(例如每个文件读取几MB)
  • 建立最小堆(优先队列)来追踪当前每个文件的最小值
  • 每次从堆中取出最小值,写入输出文件
  • 从该最小值所在的文件再读入一个ID到堆中
  • 重复上述过程直到所有文件都处理完

具体示例:

  • 分批归并:每轮合并50个分块(50路归并),共需4轮(200/50)
  • 堆排序优化:使用 最小堆(PriorityQueue) 管理各分块当前读取值

内存管理:

输入缓冲区

800MB

每个分块预读16MB(50分块×16MB)

输出缓冲区

200MB

写满后批量刷新至磁盘

3.核心代码(Java实现)

阶段1:分割大文件,并排序小文件,输出多个小文件排序后的结果

private static List<File> splitAndSort(String inputFile) throws IOException {
        List<File> chunks = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(inputFile))) {
            List<Long> buffer = new ArrayList<>(MAX_CHUNK_SIZE / 8);
            String line;
            
            while ((line = reader.readLine()) != null) {
                buffer.add(Long.parseLong(line));
                // 内存达到阈值时执行排序和写入
                if (buffer.size() >= MAX_CHUNK_SIZE / 8) {
                    chunks.add(sortAndWrite(buffer));
                    buffer.clear();
                }
            }
            // 处理剩余数据
            if (!buffer.isEmpty()) {
                chunks.add(sortAndWrite(buffer));
            }
        }
        return chunks;
    }

阶段2:多路归并,使用最小堆优化

 private static void mergeFiles(List<File> files, String output) throws IOException {
        PriorityQueue<FileEntry> minHeap = new PriorityQueue<>(
            files.size(), 
            Comparator.comparingLong(FileEntry::current)
        );

        // 初始化堆(每个文件读取一个元素)
        for (File file : files) {
            BufferedReader reader = new BufferedReader(new FileReader(file));
            String line = reader.readLine();
            if (line != null) {
                minHeap.offer(new FileEntry(Long.parseLong(line), reader));
            }
        }

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(output))) {
            while (!minHeap.isEmpty()) {
                FileEntry entry = minHeap.poll();
                writer.write(entry.current.toString());
                writer.newLine();
                
                // 从当前文件读取下一个元素
                String line = entry.reader.readLine();
                if (line != null) {
                    entry.current = Long.parseLong(line);
                    minHeap.offer(entry);
                } else {
                    entry.reader.close(); // 关闭已读完的文件
                }
            }
        }
    }

#软件开发笔面经#
全部评论

相关推荐

从输入URL到页面加载发生了什么:总体来说分为以下几个过程:&nbsp;1.DNS解析&nbsp;2.TCP连接&nbsp;3.发送HTTP请求&nbsp;4.服务器处理请求并返回HTTP报文&nbsp;5.浏览器解析渲染页面&nbsp;6.连接结束。简述了一下各个过程的输入输出作用:以下是对从输入&nbsp;URL&nbsp;到页面加载各过程的输入、输出或作用的一句话描述:DNS&nbsp;解析:&nbsp;输入:用户在浏览器地址栏输入的域名(如&nbsp;www.example.com)。输出:对应的&nbsp;IP&nbsp;地址(如&nbsp;192.168.1.1)。作用:将易于记忆的域名转换为计算机能够识别和用于网络通信的&nbsp;IP&nbsp;地址,以便浏览器与目标服务器建立连接。TCP&nbsp;连接:&nbsp;输入:浏览器获得的服务器...
明天不下雨了:参考一下我的说法: 关键要讲出输入网址后涉及的每一个网络协议的工作原理和作用: 涉及到的网络协议: HTTP/HTTPS协议->DNS协议->TCP协议->IP协议->ARP协议 面试参考回答: 第一次访问(本地没有缓存时): 一般我们在浏览器地址栏输入的是一个域名。 浏览器会先解析 URL、解析出域名、资源路径、端口等信息、然后构造 HTTP 请求报文。浏览器新开一个网络线程发起HTTP请求(应用层) 接着进行域名解析、将域名解析为 IP 地址 浏览器会先检查本地缓存(包括浏览器 DNS 缓存、操作系统缓存等)是否已解析过该域名 如果没有、则向本地 DNS 服务器请求解析; 本地服务器查不到会向更上层的 DNS 服务器(根域名服务器->顶级域名服务器->权威域名服务器询问)递归查询 最终返回该域名对应的 IP 地址。(应用层DNS协议)DNS 协议的作用: 将域名转换为 IP 地址。 由于 HTTP 是基于 TCP 传输的、所以在发送 HTTP 请求前、需要进行三次握手、在客户端发送第一次握手的时候、( 浏览器向服务器发送一个SYN(同步)报文、其中包含客户端的初始序列号。TCP头部设置SYN标志位、并指定客户端端口 同时填上目标端口和源端口的信息。源端口是浏览器随机生成的、目标端口要看是 HTTP 还是 HTTPS、如果是 HTTP 默认目标端口是 80、如果是 HTTPS 默认是 443。(传输层) 然后到网络层:涉及到(IP协议) 会将TCP报文封装成IP数据包、添加IP头部,包含源IP地址(浏览器)和目标IP地址(服务器)。IP 协议的作用: 提供无连接的、不可靠的数据包传输服务。 然后到数据链路层、会通过 ARP 协议、获取目标的路由器的 MAC 地址、然后会加上 MAC 头、填上目标 MAC 地址和源 MAC 地址。 然后到物理层之后、直接把数据包、转发给路由器、路由器再通过下一跳、最终找到目标服务器、然后目标服务器收到客户的 SYN 报文后,会响应第二次握手。 当双方都完成三次握手后、如果是 HTTP 协议、客户端就会将 HTTP 请求就会发送给目标服务器。如果是 HTTPS 协议、客户端还要和服务端进行 TLS 四次握手之后、客户端才会将 HTTP 报文发送给目标服务器。 目标服务器收到 HTTP 请求消息后、就返回 HTTP 响应消息、浏览器会对响应消息进行解析渲染、呈现给用户
点赞 评论 收藏
分享
03-05 12:52
吉林大学 Java
挣K存W养DOG:他的价值在于把他家里积攒的财富回馈给社会
点赞 评论 收藏
分享
评论
3
26
分享

创作者周榜

更多
牛客网
牛客企业服务