实现List接口的ArrayList和LinkedList.

实现List接口的ArrayList和LinkedList

前言:最近开始秋招,对于秋招中数据结构是重要的一个核心考点,为了能对以前所学知识的复习和回顾,我将会从今天开始持续更新总结数据结构其中部分核心的知识点,希望能帮助大家在复习时提高效率,快速回顾。如果觉得有用的话就点个小小的赞吧!感谢!!!

首先是ArrayList和LinkedList在List接口中的实现图

在这里插入图片描述
如上图是利用IDEA查询一个类或者接口他们的父类或者实现的方式
ArrayList的实现情况图:
在这里插入图片描述
LinkedList的实现情况图:
在这里插入图片描述
总的来说都是实现了List接口,不同的是ArrayList和LinkedList实现的方式不一样,ArrayList底层实现是数组的形式,LinkedList实现底层是链表的形式。
接下来对于两者的情况各自展开讲解:

ArrayList

首先我们知道ArrayList底层实现是基于数组的形式,那么对于数组来说在创建的时候肯定会先进行容量空间的分配,所以在ArrayList的源码中他的初始容量设置如下:
ArrayLsit初始容量
从上图不难看出ArrayList在创建的时候容量默认是10
但是在运用的过程中容量肯定不够,就需要考虑扩容的问题,在源码中扩容机制是这样进行实现的:
在这里插入图片描述
解读上面的代码可以看出ArrayList的扩容机制是:
newCapacity=oldCapacity+(oldCapacity>>1);
就是 新的容量=旧容量+旧容量/2。 即就是1.5倍的扩容机制
在整体的的源码中扩容机制是如下的:
初步预估按照1.5倍大小扩容
如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容
真正扩容之前检测是否能扩容成功,防止太大导致扩容失败

ArrayList使用实现的API
API 实现效果
void add(int index, E element) 将 e 插入到 index 位置
boolean add(E e) 尾插 e
E remove(int index) 删除 index 位置元素
boolean remove(Object o) 删除遇到的第一个 o
E get(int index) 获取下标 index 位置元素
void clear() 清空
E set(int index, E element) 将下标 index 位置元素设置为 element
boolean contains(Object o) 判断 o 是否在线性表中
int indexOf(Object o) 返回第一个 o 所在下标
int lastIndexOf(Object o) 返回最后一个 o 所在下标
List subList(int fromIndex, int toIndex) 截取部分List

当然对于常用的API都是基于数组来实现的,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。

LinkedList

在谈到LinkedList的时候,则其底层实现就是双向链表的形式进行。
谈到链表,则链表是一种物理存储结构上不一定连续,但是,元素的逻辑顺序是连续的。具体的实现链表方式有单向链表,双向链表,循环链表。
对于单向链表、双向链表、环形链表的表现的形式如下图:
单向链表:
在这里插入图片描述
双向链表:
在这里插入图片描述
循环链表:
在这里插入图片描述
在LinkedList中对于元素空间的创建时不需要采用ArrayList那样去提前分配空间,其底层采用双向链表的形式,则在添加和删除元素的时候只需要去更新当前元素的下一个元素和当前元素的前一个元素所存放的地址信息即可。
同时由于底层实现是通过链表的形式,在其进行元素的访问和搜索的时候就需要一个一个的进行遍历,因此LinkedList不支持进行随机访问,但是在任意位置进行插入和删除操作的时候效率较高,时间复杂度为O(1)。

LinkedList常用的API
API 实现效果
void add(int index, E element) 将 e 插入到 index 位置
boolean add(E e) 尾插 e
E remove(int index) 删除 index 位置元素
boolean remove(Object o) 删除遇到的第一个 o
E get(int index) 获取下标 index 位置元素
void clear() 清空
E set(int index, E element) 将下标 index 位置元素设置为 element
boolean contains(Object o) 判断 o 是否在线性表中
int indexOf(Object o) 返回第一个 o 所在下标
int lastIndexOf(Object o) 返回最后一个 o 所在下标
List subList(int fromIndex, int toIndex) 截取部分List

ArrayList和LinkedList时间复杂度度和空间复杂度分析:
获取元素get():
ArrayList直接进行读取 时间复杂度为O(1)
LinkedList需要进行遍历获取元素 时间复杂度为O(n)
添加元素add():
ArrayList在后面之间进行添加 时间复杂度为O(1) 空间复杂度O(1)
LinkedList添加到最后的位置 时间复杂度为O(1) 空间复杂度O(1)
添加元素add(index,E):
ArrayList 在index位置添加,同时后面元素需要后移 时间、空间复杂度为O(n)
LinkedList 在index位置添加 时间复杂度为O(1)、空间复杂度O(1)
删除元素remove(index,E):
ArrayList 在index位置进行删除,移动后面的元素 时间、空间复杂度为O(n)
LinkedList 直接在该位置进行删除,连接后面的元素即可 时间、空间复杂度为O(1)
最后总结一下:
ArrayList应用于元素高效存储+频繁访问的状态下。它的物理地址连续,并且支持随机访问,元素空间不够的时候需要进行扩容。 但是对于任意位置插入和删除操作,效率低,可能需要搬移元素才能实现。
LinkedList应用于在任意位置插入和删除频繁的场景下。它的物理地址不一定连续,但是打的逻辑地址一定连续,不支持随机访问。但是在插入、删除操作的时候仅仅需要改变引用的地址信息就可实现。因此对于LinkedList来说容量空间不需要进行考虑。

猜你喜欢

转载自blog.csdn.net/qq_53699052/article/details/126719555