集合拆分不注意写法性能差距真的很大

问题描述

场景:解析数据包中的数据长度,按照完整的数据包进行分组执行(子包不能被拆分)。

数组拆分说明:

假设数组: {{1, 2, 3, ,4 ,5 ,6, 7, 8}, {1, 2, 3, 4}, {1, 2}} 按照给定的 limit 拆分成为多个二维数组

示例1: 如果传入2分为 3 个数组

{{1, 2, 3, ,4 ,5 ,6, 7, 8}}

{{1, 2, 3, 4}}

{{1, 2,}}

示例2: 如果传入6分为 2 个数组

{{1, 2, 3, ,4 ,5 ,6, 7, 8}}

{{1, 2, 3, 4}, {1, 2,}}

示例3:如果传入1分为 2 个数组

{{1, 2, 3, ,4 ,5 ,6, 7, 8}}

{{1, 2, 3, 4}}

{{1, 2}}

说明:一般数据长度在 5000 左右

第一版代码

第一版本代码,其实是最容易想到的,咱们就顺着遍历,然后每次往最后一个集合里面放,比较复杂的就是边界处理, 大致逻辑如下:

  1. 对 resultList[0] 赋初始值;
  2. currSize 记录当前累计的数量;
  3. 当前的数据放入 resultList 的最后一个子元素中;
  4. 获取下一个元素的长度;
  5. 判断是否达到阈值,达到阈值就创建新的集合中,此处需要注意是否越界。
java 复制代码
private List<List<List<Integer>>> partition(List<List<Integer>> dataList, int limit) {
    List<List<List<Integer>>> resultList = new ArrayList<>();
    int currSize = 0;
    resultList.add(new ArrayList<>());
    for (int i = 0; i < size; i++) {
        resultList.get(dataList.size() - 1).add(dataList.get(i));
        currSize += subResultList.size();
        int nextSize = (i >= dataList.size() - 1) ? 0 : dataList.get(i + 1).size();
        if (currSize + nextSize >= limit && i < size - 1) {
            resultList.add(new ArrayList<>());
            currSize=0;
        }
    }
    return resultList;
}

优化后版本

这个版本就优化了很多,简化了边界处理,以及 get 集合的操作大致逻辑如下:

  1. 如果是 currTotal = 0,就添加一个空集合 resultList 的最后一个元素,并且复位 currTotal = currSize
  2. 在后续循环中,如果 currTotal + currSize > limit 也同样处理
  3. 其他情况 currTotal += currSize
  4. 最后将当前集合添加到 resultList的最后一个元素中
java 复制代码
private List<List<Integer>> partition(List<List<Integer>> dataList, int limit) {
    LinkedList<List<List<Integer>>> resultList = new LinkedList<>();
    int currTotal = 0;
    for (List<Integer> subList : dataList) {
        int currSize = subList.size();
        if (currTotal == 0 || currTotal + currSize > limit) {
            currTotal = currSize;
            resultList.add(new LinkedList<>());
        } else {
            currTotal += currSize;
        }
        resultList.getLast().add(subList);
    }
    return resultList;
}

优化总结

  1. 数据结构上使用, 使用 ArrayList 会拓容,会存在性能开销,LinkedList 底层是链表结构。
  2. 结构上简化,第一种使用探测的方式,需要提前访问下个节点的数据,访问次数 2*n, 第二种只需要访问 n 次,性能提升一倍。
  3. 注意细节,有时候不起眼的地方就是最危险的地方。
相关推荐
JH30733 小时前
SpringBoot 优雅处理金额格式化:拦截器+自定义注解方案
java·spring boot·spring
颜酱4 小时前
图结构完全解析:从基础概念到遍历实现
javascript·后端·算法
Coder_Boy_4 小时前
技术让开发更轻松的底层矛盾
java·大数据·数据库·人工智能·深度学习
invicinble5 小时前
对tomcat的提供的功能与底层拓扑结构与实现机制的理解
java·tomcat
较真的菜鸟5 小时前
使用ASM和agent监控属性变化
java
黎雁·泠崖5 小时前
【魔法森林冒险】5/14 Allen类(三):任务进度与状态管理
java·开发语言
qq_12498707536 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_6 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
Mr_sun.6 小时前
Day06——权限认证-项目集成
java
瑶山6 小时前
Spring Cloud微服务搭建四、集成RocketMQ消息队列
java·spring cloud·微服务·rocketmq·dashboard