技巧:ArrayList删除元素时, 从尾部开始遍历,可大大提升执行效率,arraylist大大提升
技巧:ArrayList删除元素时, 从尾部开始遍历,可大大提升执行效率,arraylist大大提升
一.描述:
1. 工作中,常常遇到这样的要求: 将列表里符合(或不符合)某条件的元素删除, 如:
有列表list = [ "a", "b", "c", "d" ], 删除其中的"a", "b", "c"
2. 关键在于遍历: 建议从尾部开始, 取代常规的从头部开始
3. 有人会说 使用 LinkedList 更合适 -- 此处只考虑 ArrayList;
二.推断:
当 list 删除元素 "a" 之后, 变为 [ "b", "c", "d" ], 猜想, list 内部数组发生变化(内存的变化):
list(1) --> list(0),
list(2) --> list(1),
list(3) --> list(2),
list(4)删除
list(n):表示list内部数组的元素;
--> :表示复制到,或移动到
三.证明:
查看源码java.util.ArrayList.remove()
Java代码
- public E remove(int index) {
- RangeCheck(index);
- modCount++;
- E oldValue = (E) elementData[index];
- int numMoved = size - index - 1;
- if (numMoved > 0)
- System.arraycopy(elementData, index + 1, elementData, index, numMoved);
- elementData[--size] = null; // Let gc do its work
- return oldValue;
- }
里面的System.arraycopy(),正是将 欲删除的元素 后面的 元素, 依次向前移动一个位置(内存), 最后再将
最后一个元素删除(值空, 删除由GC处理).
与预想的吻合.
四.分析:
1.从list头部开始遍历:
列表元素 删除元素 操作后列表元素 内存移动次数
----------------------------------------------------------------------------------------------------
[ "a", "b", "c", "d" ] "a" [ "b", "c", "d" ] 3
[ "b", "c", "d" ] "b" [ "c", "d" ] 2
[ "c", "d" ] "c" [ "d" ] 1
----------------------------------------------------------------------------------------------------
合计 6
2.从list尾部开始遍历:
列表元素 删除元素 操作后列表元素 内存移动次数
----------------------------------------------------------------------------------------------------
[ "a", "b", "c", "d" ] "c" [ "a", "b", "d" ] 1
[ "a", "b", "d" ] "b" [ "a", "d" ] 1
[ "a", "d" ] "a" [ "d" ] 1
----------------------------------------------------------------------------------------------------
合计 3
3.综上两点, 从list尾部开始遍历 可以减少底层的操作次数, 提高程序执行得效率.
五.实践:
此例, 删除了99999个元素(共100000), 免得有人投机取巧用clear,当然用clear是最快的,因为不涉及内存移动.
Java代码
- import java.util.ArrayList;
- import java.util.List;
- public class $ {
- private static int MAX = 100000;
- public static void main(String[] args) {
- System.out.println("容量:" + MAX);
- removeFromF();
- removeFromL();
- }
- private static void removeFromF() {
- List data = initData();
- long l0 = System.currentTimeMillis();
- for (int i = 0; i < data.size() - 2; i++) {
- data.remove(i);
- }
- long l1 = System.currentTimeMillis();
- System.out.println("从前往后remove(留下最后一个):" + (l1 - l0) + "MS");
- }
- private static void removeFromL() {
- List data = initData();
- long l0 = System.currentTimeMillis();
- for (int i = data.size() - 2; i >= 0; i--) {
- data.remove(i);
- }
- long l1 = System.currentTimeMillis();
- System.out.println("从后往前remove(留下最后一个):" + (l1 - l0) + "MS");
- }
- private static List initData() {
- List data = new ArrayList();
- for (int i = 0; i < MAX; i++) {
- data.add(i);
- }
- return data;
- }
- }
结果:
Java代码
- 容量:100000
- 从前往后remove(留下最后一个):3596MS
- 从后往前remove(留下最后一个):6MS
这耗时, 不是一个数量级的,随着数据增大, 差距越明显.
六.番外:
随便记一下:
Java代码
- public E remove(int index) {
- RangeCheck(index);
- modCount++;
- E oldValue = (E) elementData[index];
- int numMoved = size - index - 1;
- if (numMoved > 0)
- System.arraycopy(elementData, index + 1, elementData, index, numMoved);
- elementData[--size] = null; // Let gc do its work
- return oldValue;
- }
当做其删除操作时, list 内部数组的大小是没有变化的(假如此时GC尚未工作), 变化的只是size, 而在外部我们能得到的
是size, 最多也只能得到 0 ~ size-1 的元素.
七:扩展:
手动删除excel列时,也建议 从后面开始删. 源码没有看过,是根据现象猜测的.
举例:
excel2007 (2003没试过,猜想应该是一样的)
从A ~ BB列, 20000行数据, 删除其中的A列 和 BB列, 看看哪个快?
有兴趣可试试....
相关文章
- 暂无相关文章
用户点评