likes
comments
collection
share

集合拆分的代码简单优化

作者站长头像
站长
· 阅读数 18

问题描述

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

数组拆分说明:

假设数组: {{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. 判断是否达到阈值,达到阈值就创建新的集合中,此处需要注意是否越界。
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的最后一个元素中
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. 注意细节,有时候不起眼的地方就是最危险的地方。