1.表的简单数组实现
对表的所有这些操作都可以通过使用数组来实现。
虽然数组是由固定容量创建的,但在需要的时候可以用双倍的容量创建一个不同的数组。
它解决了由于使用数组而产生的最严重的问题,即为了使用一个数组,需要对表的大小进行估计
数组的扩展实例:
int[] arr = new int[10];
int[] newarr = new int[arr.length * 2];
for (int i = 0; i < arr.length; i++) {
newarr[i] = arr[i];
}
arr = newarr;
数组的实现,
- 可以使得pringtlist以线性的时间被执行
- findKth则花费常数的时间
- 插入和删除操作的花费则潜藏昂贵的开销(需要大量的移动数组中的元素)
如果对表的插入和删除操作都是在表的后端进行的,其后只发生对表的访问(即findKth),那么数组是一个恰当的实现
ArrayList类提供了List ADT的一种可增长数组的实现。
- 优点在于,对get和set的调用花费常数时间
- 缺点在于,新项的插入和现有项的删除代价昂贵,除非变动是在ArrayList的末端进行
2.表的简单链表实现
为了避免插入和删除的线性开销,需要保证表可以不连续存储,否则表的每个部分都可能需要整体移动。
链表由一系列节点组成,这些节点不必在内存中相连。每个节点均含有表元素和到包含该元素后继元的节点的链(link),称之为next链,最后一个单元的next链引用null。
链表的实现,
- 执行printlist和find(K),只要从表的第一个节点开始用一些后继的next链遍历该表即可
- findKth不如数组实现的高效,需要从头遍历到第K个
- remove方法可以通过修改一个next引用来实现
- insert方法需要使用new操作符从系统取得一个新节点,然后执行2次引用的调整
- 在表的前端插入和删除一个项的特殊操作都属于常数时间的操作
- 如果知道链表的最后一个节点,那么在链表末尾的操作也是常数时间的操作
如果对表的插入和删除操作都是在表的前端进行,那么链表是一个恰当的实现
LinkedList类提供了List ADT的双链表实现。
- 优点在于,新项的插入和现有项的删除均开销很小,假设变动的位置已知(否则需要遍历)
- 缺点在于,get和set需要遍历,不容易做索引