ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时,需要增加存储能力,就要将已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动时,代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
List
常用的List方法:
- add 在最后或特定位置加入新的元素
- clear 清除所有元素
- contains 是否含有指定元素
- get 获取特定索引元素
- indexOf 返回特定元素第一次出现的索引,没有则返回-1
- lastIndexOf 返回特定元素最后一次出现的索引,没有则返回-1
- isEmpty 判断是否为空
- iterator 返回迭代器
- remove 移除特定元素
- size 返回List大小
- subList 根据传入的两个索引返回子列表
常用的List实现类有:
- ArrayList: 擅长随机访问的列表
- LinkedList: 擅长插入和删除操作的列表
- Vector: 与ArrayList类似,线程安全的列表
MyArrayList和MyLinkedList
可以使用ArrayList和LinkedList来存储线性表。使用数组实现ArrayList,使用链表实现LinkedList,前者开销比后者小。但是如果需要在线性表的开始位置插入和删除元素,那么LinkedList的效率会高一点。下表总结了ArrayList和LinkedList中方法的时间复杂度。
方法 | ArrayList | LinkedList |
---|---|---|
add(e: E) | O(1) | O(1) |
add(index: int, e: E) | O(n) | O(n) |
clear() | O(1) | O(1) |
contains(e: E) | O(n) | O(n) |
get(index: int) | O(1)** | O(n) |
indexOf(e: E) | O(n) | O(n) |
isEmpty() | O(1) | O(1) |
lastIndexOf(e: E) | O(n) | O(n) |
remove(e: E) | O(n) | O(n) |
size() | O(1) | O(1) |
remove(index: int) | O(n) | O(n) |
set(index: int, e: E) | O(n) | O(n) |
addFirst(e: E) | O(n) | O(1)** |
removeFirst() | O(n) | O(1)** |
ArrayList部分细节
使用数组来实现动态数据结构,处理方法是:当数组不能再存储线性表的新元素时,创建一个更大的新数组来替换当前数组。
add(int index, E e)
1 | public void add(int index, E e) { |
clear()
通过创建一个新数组并且将其复制给data,老的数组和保存在数组中的数据变成垃圾,将自动被JVM回收。
1 | public void clear() { |
remove(int index)
最后一个元素不再使用,设置为null。
1 | public E remove(int index) { |
ArrayList具体实现
采用集合的实现模式,在MyList接口中提供通用的操作,抽象类部分实现了包括集合操作的addAll、removeAll和containsAll等方法,最后在MyArrayList类中实现了数组线性表。
为了便于手机查看,采用倒序的显示方式。将接口、抽象类和测试用例放在最后。
1 | package algorithms.arrayList; |
接口、抽象类和测试用例
MyList接口
1 | package algorithms.arrayList; |
MyAbstractList抽象类
1 | package algorithms.arrayList; |
MyArrayList测试用例
1 | package algorithms.arrayList; |