顺序表与ArrayList
1.顺序表
1.1概念以及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:
- 静态顺序表:使用定长数组存储。
- 动态顺序表:使用动态开辟的数组存储。
1.2自己实现一个顺序表
-
基本结构
public class MyArrayList<E> { private E[] value; private int usedsize; private static final int DEFAULT_SIZE = 10; public MyArrayList() { this.value = (E[]) new Object[DEFAULT_SIZE]; } }
-
打印顺序表
public void display() { for (int i = 0; i < this.usedsize; i++) { System.out.println(value[i] + " "); } }
-
增加元素
public void add(E data) { if (isFull()) { this.value = Arrays.copyOf(this.value, this.value.length * 2); } this.value[usedsize] = data; usedsize++; } private boolean isFull() { return usedsize >= value.length; }
-
删除元素
public void remove(E toRemove) throws Exception { if (isEmpty()) { throw new Exception("表为空"); } int index = indexOf(toRemove); if (index == -1) { throw new Exception("要删除的元素不存在"); } for (int j = index; j < usedsize - 1; j++) { this.value[j] = this.value[j + 1]; } this.usedsize--; } public boolean isEmpty() { if (usedsize == 0) { return true; } return false; }
-
判定是否包含某个元素
public boolean contains(E toFind) { for (int i = 0; i < this.usedsize; i++) { if (value[i].equals(toFind)) { return true; } } return false; }
-
查找某个元素的位置
public int indexOf(E toFind) { for (int i = 0; i < this.usedsize; i++) { if (value[i].equals(toFind)) { return i; } } return -1; }
-
获取顺序表的长度
public int size() { return this.usedsize; }
-
清空顺序表
public void clear() { for (int i = 0; i < this.usedsize; i++) { this.value[i] = null; } usedsize = 0; }
-
获取指定位置的元素
public E get(int pos) throws Exception { if (isEmpty()) { throw new Exception("表为空"); } if (pos < 0 || pos > usedsize) { throw new Exception("下标不合法"); } return this.value[pos]; }
-
给指定位置的元素设为 value
public void set(int pos, E value) throws Exception {
if (isEmpty()) {
throw new Exception("表为空");
}
if (pos < 0 || pos > usedsize) {
throw new Exception("更新位置不合法");
}
this.value[pos] = value;
}
2.ArrayList集合类
2.1基本概念
- ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
- ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
- ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
- 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者
CopyOnWriteArrayList - ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表
2.2ArrayList构造方法
方法 | 解释 |
---|---|
ArrayList() | 无参构造 |
ArrayList(Collection<? extends E> c) | 利用其他 实现Collection的类 构建 ArrayList |
ArrayList(int initialCapacity) | 指定顺序表初始容量 |
2.3ArrayList的基本操作
方法 | 解释 |
---|---|
boolean add(E e) | 尾插 e |
void add(int index, E element) | 将 e 插入到 index 位置 |
boolean addAll(Collection<? extends E> c) | 尾插 c 中的元素 |
E remove(int index) | 删除 index 位置元素 |
boolean remove(Object o) | 删除遇到的第一个 o |
E get(int index) | 获取下标 index 位置元素 |
E set(int index, E element) | 将下标 index 位置元素设置为 element |
void clear() | 清空 |
boolean contains(Object o) | 判断 o 是否在线性表中 |
int indexOf(Object o) | 返回第一个 o 所在下标 |
int lastIndexOf(Object o) | 返回最后一个 o 的下标 |
List subList(int fromIndex, int toIndex) | 截取部分 list |
2.4ArrayList的遍历
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
// 使用下标+for遍历
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
System.out.println();
// 借助foreach遍历
for (Integer integer : list) {
System.out.print(integer + " ");
}
System.out.println();
Iterator<Integer> it = list.listIterator();
while(it.hasNext()){
System.out.print(it.next() + " ");
}
System.out.println();
}
2.5ArrayList的扩容机制
- 检测是否真正需要扩容,如果是调用grow准备扩容
- 预估需要库容的大小
- 初步预估按照1.5倍大小扩容
- 如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容
- 真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
- 使用copyOf进行扩容