ArrayList && LinkedList

目录

前言

1.ArrayList简介 

2.ArrayList的相关使用 

ArrayList的构造

ArrayList常见操作 

ArrayList的遍历 

ArrayList的扩容机制 

ArrayList的问题及思考 

3.问题 

那么如何解决上述出现的问题呢?

4.链表 

5.LinkedList的使用 

什么是LinkedList 

LinkedList的使用 

LinkedList的构造 

LinkedList的其他常用方法

LinkedList的遍历

ArrayList和LinkedList的区别  


前言

本篇博客将详细讲述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。
 

  • 37
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱编程的Tom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值