看到这么一段代码
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 个元素,广告一般情况下会有两个,所以大部分情况下:
- 触发一次扩容 + 一次列表拷贝
- 插入第一个广告时,后续的元素被全量拷贝到新位置
- 插入第二个广告,同上
一般做过算法题的同学会怎么写呢,
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;
}
大多数人也许会说这么点性能不重要,嗯~~~