前言
集合框架
java集合框架又被称为容器,是定义在java.util包下的一组接口和其实现类,主要是将多个元素放进一个对象中,以便对这些元素进行管理即增删查改(CRUD)操作。
👉使用成熟的集合框架,有助于然我们便捷 快速的编写出有效 稳定的代码
👉学习和了解背后的数据结构,可以帮助我们理解集合框架的优缺点,以及使用场景
线性表
- 线性表是由n个具有相同特性的元素的有序序列,是一种常见的数据结构 常见的有:顺序表 链表 栈 队列 …
- 线性表是在逻辑上连续的,呈一条直线,但在物理上不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
顺序表
顺序表是在物理地址上连续的依次存储数据的线性结构,一般情况下采用数组进行存储,在数组上完成对数据的增删查改操作。
ArrayList简介
在集合框架中,ArrayList是一个普通的类,实现了一些接口,具体框架图如下:
说明:👇👇
- ArrayList是以泛型的方式实现的,使用的时候必须实例化
- Array List实现了RandomAccess接口,表示ArrayList支持随机访问
- 实现了Clone able接口,表明可以克隆的
- 实现了Serializable接口,表明支持序列化的
- 不是线程安全的,单线程下使用,
- 底层时一段连续的空间,可以动态扩容,可以理解为是一个数组
ArrayList使用
ArrayList的构造方法
方法 | 解释 |
---|---|
ArrayList() | 无参构造 |
ArrayList(int initialCapacity) | 指定顺序表的初始容量 |
ArrayList(Collection<? extends E> c) | 使用Collection实现类构造ArrayList |
public static void main(String[] args) {
//推荐写法
//无参构造 -- 一个空的顺序表
List<Integer> list1 = new ArrayList<>();
//初始化一个容量为10的一个顺序表
List<Integer> list2 = new ArrayList<>(10);
list2.add(1);
list2.add(2);
//把list2作为参数来初始化构造list3
List<Integer> list3 = new ArrayList<>(list2);
}
ArrayList常用的方法
//尾插 e
boolean add(E e)
//将 e 插入到 index 位置
void add(int index, E element)
//尾插 c 中的元素
boolean addAll(Collection<? extends E> c)
//删除 index 位置元素
E remove(int index)
//删除遇到的第一个 o
boolean remove(Object o)
//获取下标 index 位置元素
E get(int index)
//将下标 index 位置元素设置为 element
E set(int index, E element)
//清空
void clear()
//判断 o 是否在线性表中
boolean contains(Object o)
//返回第一个 o 所在下标
int indexOf(Object o)
//返回最后一个 o 的下标
int lastIndexOf(Object o)
//截取部分 list
List<E> subList(int fromIndex, int toIndex)
模拟实现ArrayList顺序表
为什么要模拟实现?
通过模拟实现代码的过程中,我们可以更深刻地了解代码实现的逻辑,加深对代码的印象
在java内部的ArrayList是一个泛型的
因为我们只需要了解代码的逻辑,为了方便,所以这里用整形举例
public class MyArrayList {
public int[] elem; //虽然ArrayList底层可能不是数组,为了方便这里使用数组存储
public int usedSize; //用来记录当前数组内的有效数据个数,初始化默认为0
public static int DEFAULT_SIZE = 10; //数组默认大小
public MyArrayList(){
this.elem = new int[DEFAULT_SIZE];
}
// 获取顺序表长度
public int size() {
return this.usedSize;
}
// 判定是否包含某个元素
public boolean contains(int toFind) {
for (int i = 0; i < this.usedSize; i++) {
if (this.elem[i] == toFind) { //如果是引用类型就不能使用==号判断了
return true;
}
}
return false;
}
// 查找某个元素对应的位置
public int indexOf(int toFind) {
for (int i = 0; i < this.usedSize; i++) {
if (this.elem[i] == toFind) { //如果是引用类型就不能使用==号判断了
return i;
}
}
return -1;
}
// 获取 pos 位置的元素
public int get(int pos) {
inspectGetIndex(pos);
return this.elem[pos];
}
//判断Get位置的合法性
private void inspectGetIndex(int pos) {
if(pos < 0 || pos >= this.usedSize) {
throw new IndexOutOfException("位置不合法!");
}
}
// 新增元素,默认在数组最后新增
public void add(int data) {
if(isFull()) {
//扩容
this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
//这里采用2倍扩容
}
this.elem[this.usedSize] = data;
this.usedSize++;
}
//判断数组是否满了
private boolean isFull() {
return this.usedSize == this.elem.length;
}
// 在 pos 位置新增元素
public void add(int pos, int data) {
//检查POS位置的合法性
inspectAddIndex(pos);
if(isFull()) {
//扩容
this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
}
int last = this.usedSize-1;
for (int i = pos; i <= last;) {
this.elem[last+1] = this.elem[last];
last--;
}
this.elem[pos] = data;
usedSize++;
}
//判断add中POS位置的合法性
private void inspectAddIndex(int pos) {
if(pos < 0 || pos > this.elem.length) {
throw new IndexOutOfException("位置不合法!");
}
}
// 给 pos 位置的元素设为 value
public void set(int pos, int value) {
inspectSetIndex(pos);
this.elem[pos] = value;
}
private void inspectSetIndex(int pos) {
if(pos < 0 || pos > this.elem.length) {
throw new IndexOutOfException("位置不合法!");
}
}
//删除第一次出现的关键字key
public void remove(int toRemove) {
if (contains(toRemove)) {
//把后面元素向前覆盖
for (int i = indexOf(toRemove); i < this.usedSize-1; i++) {
this.elem[i] = this.elem[i+1];
}
this.usedSize--;
this.elem[usedSize] = 0;
} else {
System.out.println("没有这个数!");
}
}
// 清空顺序表
public void clear() {
for (int i = 0; i < this.usedSize; i++) {
this.elem[i] = 0;
}
this.usedSize = 0;
}
}