一.描述:
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()
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是最快的,因为不涉及内存移动.
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; } }
结果:
容量:100000 从前往后remove(留下最后一个):3596MS 从后往前remove(留下最后一个):6MS
这耗时, 不是一个数量级的,随着数据增大, 差距越明显.
六.番外:
随便记一下:
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列, 看看哪个快?
有兴趣可试试....
相关推荐
- LinkedList的get操作相对较慢,因为需要从头或尾部开始遍历直到目标位置,时间复杂度为O(n)。 3. 插入和删除性能: - 在ArrayList中插入或删除元素时,可能需要移动后续元素来保持数组的连续性。如果插入或删除...
5. **效率考虑**: ArrayList内部基于动态数组实现,因此在尾部添加元素时效率较高。但如果在中间或开头插入或删除元素,可能需要移动大量元素,效率较低。如果插入和删除操作频繁,考虑使用LinkedList。 6. **线程...
5. **异常处理**:在执行批量删除时,应捕获并处理可能出现的异常,例如`NoSuchElementException`或`ConcurrentModificationException`。 6. **性能考量**:批量删除操作的时间复杂度与所选数据结构和删除策略有关...
- LinkedList基于双向链表,插入和删除操作在任何位置都很高效,但访问元素时需要从头或尾部开始遍历,效率低。 4. **Array vs ArrayList**:Array是原生的Java数组,而ArrayList是集合框架中的类,基于数组实现,...
- **删除方法(Deletion)**:从数组中移除元素。 - `RemoveAt`:根据索引移除元素。 - `Remove`:移除特定值的所有匹配项。 - **索引操作(Indexing)**: - `IndexOf`:查找特定元素的索引。 - `Item`:通过...
动态数组(如ArrayList)支持随机访问,但插入和删除在非尾部位置较慢,需移动元素。对于1k数据的随机存取,若访问频繁,动态数组更合适;若插入和删除频繁,链表可能更适合。 9. 字节序:字节序是指多字节数据类型...
ArrayList基于动态数组实现,提供了快速的随机访问,但插入和删除元素时效率相对较低,因为需要移动大量元素。相比之下,LinkedList采用链表结构,插入和删除操作速度快,但随机访问性能较差,因为需要从头或尾部...
- **插入与删除效率**:在尾部插入和删除元素速度较快,但在中间或头部操作则较慢,因为需要移动后续元素。 2. **创建ArrayList** ```java ArrayList<String> list = new ArrayList(); ``` 或者指定初始容量:...
LinkedList不同于ArrayList,它的内部是以链表的形式存储元素,因此在插入和删除操作上具有较高的效率,但在随机访问元素时性能相对较差。LinkedList包含节点(Node)对象,每个节点都包含一个数据元素和对下一个...
Java中的LinkedList实现了List接口,提供了高效的插入和删除操作,但在随机访问元素时效率较低,因为需要从头开始遍历。链表分为单向链表和双向链表,其中双向链表可以向前和向后遍历。 4. **栈**:栈是一种后进先...
对于频繁的插入和删除操作,LinkedList表现更优,但在随机访问时性能较差,因为需要从头或尾部开始遍历。 3. **Vector**: Vector与ArrayList类似,也是基于数组实现的,但它线程安全。在多线程环境下,Vector是一个...
ArrayList是基于数组实现的,因此可以快速访问任何位置的元素,其索引是从0开始的。它的主要优点是插入和删除元素时,如果位置靠近数组尾部,性能较好。然而,如果在数组中间进行插入或删除操作,由于需要移动后续...
7. **Vector类**:Vector是从JDK 1.0开始引入的,它是一个线程安全的动态数组,但性能较差,因为它的操作是同步的。ArrayList后来取代了Vector,但在某些旧项目中仍可能被使用。所以选项a和d是正确的,b和c是错误的...
然而,随机访问元素时效率较低,因为需要从头或尾部逐个遍历。 #### Collection与Collections - **概念区分**:`Collection`是所有集合类的根接口,定义了集合的基本行为。`Collections`则是一个工具类,提供了一...
1. ArrayList:基于动态数组,随机访问速度快,但在插入或删除元素时,尤其是中间位置,需要移动后续元素,效率较低。 2. LinkedList:适用于频繁插入和删除操作,因为它只需改变相邻节点的引用,但随机访问(查询)...
LinkedList基于双向链表,插入和删除操作高效,但访问元素需要从头或尾部开始遍历,速度较慢。 008异常处理机制,try-catch-finally的作用? 异常处理用于捕获和处理程序运行时可能出现的错误。try块中放置可能抛出...
每个元素包含对前一个和下一个元素的引用,因此在头部和尾部添加或删除元素非常快。 #### 3. HashMap与HashTable区别 - **数据结构基础**:`HashMap` 实现了`Map`接口,而`HashTable`继承自`Dictionary`类。 - **...
在Java编程中,`synchronized`关键字是用于实现线程同步的关键工具,它确保了多...如果一直在列表尾部添加元素,`ArrayList`的效率更高,因为它只需要简单地调整数组大小即可,而`LinkedList`需要遍历链表来找到尾部。
LinkedList则通过双向链表实现,插入和删除操作非常快,但访问元素时需要从头或尾部开始遍历,效率较低。 1. **ArrayList**: - 实现:基于数组,可以动态调整大小。 - 特点:随机访问速度快,增删元素慢(需要...
5. **ArrayList, Vector, LinkedList的特性**:ArrayList和Vector都是基于动态数组实现的列表,支持随机访问,但插入和删除元素时需要移动大量元素,效率较低。Vector是线程安全的,性能相对较差。LinkedList使用...