- 🍁 个人主页:爱编程的Tom
- 💫 本篇博文收录专栏:Java专栏
- 👉 目前其它专栏:c系列小游戏 c语言系列--万物的开始_
- 🎉 欢迎 👍点赞✍评论⭐收藏💖三连支持一下博主🤞
- 🧨现在的沉淀就是对未来的铺垫🎨
目录
前言
本篇博客将详细讲述ArrayList与LinkedList的知识以及二者之间的联系和区别......
1.ArrayList简介
关于ArrayList的框架图如下:
在集合框架中,ArrayList是一个普通的类,实现了List接口
【说明】
1. ArrayList是以泛型方式实现的,使用时必须要先实例化
2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
3. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者 CopyOnWriteArrayList
6. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表
2.ArrayList的相关使用
ArrayList的构造
下面是一个创建ArrayList的实现代码:
public static void main(String[] args) {
// ArrayList创建,推荐写法
// 构造一个空的列表
List<Integer> list1 = new ArrayList<>();
// 构造一个具有10个容量的列表
List<Integer> list2 = new ArrayList<>(10);
list2.add(1);
list2.add(2);
list2.add(3);
// list2.add("hello"); // 编译失败,List<Integer>已经限定了,list2中只能存储整形元素
// list3构造好之后,与list中的元素一致
ArrayList<Integer> list3 = new ArrayList<>(list2);
// 避免省略类型,否则:任意类型的元素都可以存放,使用时将是一场灾难
List list4 = new ArrayList();
list4.add("111");
list4.add(100);
}
ArrayList常见操作
ArrayList的遍历
ArrayList 可以使用三方方式遍历:for循环+下标、foreach、使用迭代器 ,另外此处在拓展两个。
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
LinkedList<Integer> list = new LinkedList<>(arrayList);
System.out.println(list); //第一种打印
System.out.println("===");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i)+" ");
} //第二种打印
System.out.println();
System.out.println("====");
for (int x : list) {
System.out.println(x + " ");
} //第三种打印
System.out.println();
System.out.println("===");
ListIterator<Integer> it = list.listIterator();
while (it.hasNext()) {
System.out.println(it.next()+" ");
} //第四种打印----正向迭代器
System.out.println();
System.out.println("====");
ListIterator<Integer> it2 = list.listIterator();
while (it2.hasPrevious()) {
System.out.println(it.previous()+" ");
} //第五种打印----逆向迭代器打印
System.out.println();
}
注意:
1. ArrayList最常使用的遍历方式是:for循环+下标 以及 foreach
2. 迭代器是设计模式的一种,后序容器接触多了再给大家铺垫
ArrayList的扩容机制
ArrayList是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容。
public void add(int data) {
//1.判断是否满了
if(isFull()){
elem = Arrays.copyOf(elem,2*elem.length);
}
this.elem[usedSize] = data;
usedSize++;
}
总结:
1. 检 测 是 否 真 正 需 要 扩 容 , 如 果 是 调 用 g r o w 准 备 扩 容
2. 预 估 需 要 库 容 的 大 小 初 步 预 估 按 照 1.5 倍 大 小 扩 容 如 果 用 户 所 需 大 小 超 过 预 估 1.5 倍 大 小 , 则 按 照 用 户 所 需 大 小 扩 容 真 正 扩 容 之 前 检 测 是 否 能 扩 容 成 功 , 防 止 太 大 导 致 扩 容 失 败
3. 使 用 c o p y O f进 行 扩 容
ArrayList的问题及思考
1. ArrayList底层使用连续的空间,任意位置插入或删除元素时,需要将该位置后序元素整体往前或者往后搬移,故时间复杂度为O(N)
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继 续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
3.问题
那么如何解决上述出现的问题呢?
ArrayList底层是由数组实现的,由于其是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低。
因此ArrayList不适合做任意位置插入和删除比较多的场景。
因此:java 集合中又引入LinkedList,即链表结构。
4.链表
链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。
链表的相关结构分为:单向/双向、带头/不带头、循环/不循环,即组合起来拥有8种结构
5.LinkedList的使用
什么是LinkedList
这里给出关于LinkList的相关文档:LinkedList 的官方文档
LinkedList的底层是双向链表结构,由于链表没有将元素存储在连续的空间中,元素存储在单独的节 点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。
在集合框架中,LinkedList也实现了List接口,具体如下:
几点说明:
1. LinkedList实现了List接口
2. LinkedList的底层使用了双向链表
3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
5. LinkedList比较适合任意位置插入的场景
LinkedList的使用
LinkedList的构造
public static void main(String[] args) {
// 构造一个空的LinkedList
List<Integer> list1 = new LinkedList<>();
List<String> list2 = new java.util.ArrayList<>();
list2.add("JavaSE");
list2.add("JavaWeb");
list2.add("JavaEE");
// 使用ArrayList构造LinkedList
List<String> list3 = new LinkedList<>(list2);
}
LinkedList的其他常用方法
LinkedList的遍历
这里使用迭代器来实现:
ArrayList和LinkedList的区别
我们可以结合以下几个方面来说明他们之间的区别:
数据结构:
Arraylist是基于数组实现的动态数组,可以根据需要动态调整数组的大小,但是在插入和删除操作时需要移动元素的位置。
Linkedlist是基于链表实现的,每个元素都包含一个指向下一个元素的引用,插入和删除操作比较快,但是访问元素的速度相对较慢。访问元素的速度:
Arraylist的访问速度比较快,因为可以通过索引直接访问数组中的元素。
Linkedlist的访问速度较慢,需要从头节点开始遍历链表直到找到目标元素。插入和删除操作:
Arraylist在插入和删除操作时需要移动元素的位置,时间复杂度为O(n)。
Linkedlist在插入和删除操作时只需要改变节点的引用,时间复杂度为O(1)。内存空间的占用:
Arraylist在内存中是连续存储的,所以会占用一定的内存空间。
Linkedlist在内存中是分散存储的,每个节点包含指向下一个节点的引用,可能会占用更多的内存空间。如果需要频繁进行插入和删除操作,可以选择Linkedlist;
如果需要频繁进行访问操作,可以选择Arraylist。