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

问题描述

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

数组拆分说明:

假设数组: {{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. 注意细节,有时候不起眼的地方就是最危险的地方。
相关推荐
Craaaayon7 分钟前
如何选择两种缓存更新策略(写缓存+异步写库;写数据库+异步更新缓存)
java·数据库·redis·后端·缓存·mybatis
AAA卷不动了11 分钟前
JVM(二)------ 类加载、初始化与单例模式的联系
java·jvm·单例模式
一 乐16 分钟前
点餐|智能点餐系统|基于java+ Springboot的动端的点餐系统小程序(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·小程序·论文
少许极端42 分钟前
算法奇妙屋(十)-队列+宽搜(BFS)
java·数据结构·算法·bfs·宽度优先·队列
唐僧洗头爱飘柔95271 小时前
【GORM(3)】Go的跨时代ORM框架!—— 数据库连接、配置参数;本文从0开始教会如何配置GORM的数据库
开发语言·数据库·后端·golang·gorm·orm框架·dsn
Jonathan Star1 小时前
在 Go 语言中,模板字符串
开发语言·后端·golang
程序员卷卷狗1 小时前
JVM 内存结构与 GC 调优全景图
java·开发语言·jvm
盘古开天16662 小时前
从零开始:如何搭建你的第一个简单的Flask网站
后端·python·flask
用户21411832636022 小时前
Claude Skills 从零到一:手把手打造专属公众号文风生成器,10 分钟搞定 AI 技能定制
后端
追逐时光者2 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 60 期(2025年11.1-11.9)
后端·.net