算法重要吗?(20240429)

31 阅读1分钟

看到这么一段代码

List<ItemInfo> handleDate(List<ItemInfo> data, List<AdInfo> ads) {
    if (CollectionUtils.isEmpty(ads)) {
        return data;
    }
    // 插入
    Map<Integer, AdInfo> map = EzList.toMap(ads, AdInfo::getPosition);
    for (Map.Entry<Integer, AdInfo> entry : map.entrySet()) {
        int position = entry.getKey();
        AdInfo advertDto = entry.getValue();
        if (position > data.size()) {
            continue;
        }
        ItemInfo item = new ItemInfo();
        item.setAdvertDto(advertDto);
        item.setType(2);
        item.setLocationDto(null);
        if (position - 1 <= data.size()) {
            data.add(position - 1, item);
        }
    }
    return data;
}

逻辑就是把 广告插入到列表里,乍一看好像也没什么问题

关键看这个 data.add(position - 1, item);

没有算法训练的同学可能意识不到这里有什么问题,看下 ArrayList 的源码

public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

// 容量检查,如果不够触发扩容
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

业务上其实一个列表有 30 个元素,广告一般情况下会有两个,所以大部分情况下:

  1. 触发一次扩容 + 一次列表拷贝
  2. 插入第一个广告时,后续的元素被全量拷贝到新位置
  3. 插入第二个广告,同上

一般做过算法题的同学会怎么写呢,

List<ItemInfo> insertAdInList(List<ItemInfo> items, List<AdInfo> ads) {
    if (CollectionUtils.isEmpty(ads)) {
        return items;
    }
    // 一次性分配好空间
    List<ItemInfo> newList = new ArrayList<>(items.size() + ads.size());
    ads.sort(Comparator.comparing(AdInfo::getPosition));

    int i = 0;
    Iterator<AdInfo> iterator = ads.iterator();
    AdInfo ad = iterator.next();
    // 每个一次迭代完成广告插入
    for(ItemInfo item : items) {
        if(null != ad && ad.getPosition() == i) {
            newList.add(parseItem(ad));
            ad = iterator.hasNext() ? iterator.next() : null;
        }
        i++;
        newList.add(item);
    }
    return newList;
}

大多数人也许会说这么点性能不重要,嗯~~~