ArrayList和LinkedList的区别

 一、ArrayList

 1.ArrayList简介

     在集合框架中,ArrayList是一个普通的类,实现了List接口,具体框架图如下:

eeeb6d8019b64eb28fefe1fbcf02d884.png
说明
1. ArrayList是以泛型方式实现的,使用时必须要先实例化
2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
3. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或 者CopyOnWriteArrayList
6. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

2.顺序表

     顺序表是用一段 物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成 数据的增删查改。

3.ArrayList的扩容机制

截取ArrayList源码

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// 获取旧空间大小
int oldCapacity = elementData.length;
// 预计按照1.5倍方式扩容
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果用户需要扩容大小 超过 原空间1.5倍,按照用户所需大小扩容
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果需要扩容大小超过MAX_ARRAY_SIZE,重新计算容量大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 调用copyOf扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
// 如果minCapacity小于0,抛出OutOfMemoryError异常
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
总结
1. 检测是否真正需要扩容,如果是调用grow准备扩容
2. 预估需要库容的大小
初步预估按照1.5倍大小扩容
如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容
真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
3. 使用copyOf进行扩容

4.ArrayList的缺陷

由于其底层是一段连续空间,当 ArrayList 任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后 搬移,时间复杂度为 O(n),效率比较低,因此 ArrayList 不适合做任意位置插入和删除比较多的场景。因此:java 集合中又引入了LinkedList,即链表结构。

二·、LinkedList

LInkedList本质就是一个链表!!!

2.1 链表的概念及结构

     链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。

d7635eecbc3f40cea19c4b47523d58ee.png

2.2 什么是LinkedList

    LinkedList的底层是双向链表结构(链表后面介绍),由于链表没有将元素存储在连续的空间中,元素存储在单独的节 点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。

   32372875036846e98b4d16b7a3ab1a4a.png

 afd652aefd3c42668c36ee35b3971a12.png

【说明】
1. LinkedList实现了List接口
2. LinkedList的底层使用了双向链表
3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
5. LinkedList比较适合任意位

2.3 LinkedList模拟实现

public class MyLinkedList {
    static class ListNode {
       public int val;
       ListNode prev;
       ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode head;
    public ListNode last;
    //头插法 O(1)
    public void addFirst(int data){
        ListNode node = new ListNode(data);
        if (head == null) {
            head = node;
            last = node;
        }else {
            node.next = head;
            head.prev = node;
            head = node;
        }
    }
    //尾插法 O(1)
    public void addLast(int data){
        ListNode node = new ListNode(data);
        if (head == null) {
            head = node;
            last = node;
        }else {
            last.next = node;
            node.prev = last;
            last = node;
        }
    }
    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        if (index < 0 || index >size()) {
            throw new CheckOutOfException("位置被合法");
            //return;
        }
        if (index == 0) {
            addFirst(data);
            return;
        }
        if (index == size()) {
            addLast(data);
            return;
        }
        ListNode cur = findIndex(index);
        ListNode node = new ListNode(data);
        node.next = cur;
        cur.prev.next = node;
        node.prev = cur.prev;
        cur.prev = node;
    }
    public ListNode findIndex(int index) {
        ListNode cur = head;
        while (index != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }
    //查找是否包含关键字key是否在链表当中
    public boolean contains(int key){
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    //删除第一次出现关键字为key的节点
    public void remove(int key){
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                //1.删除的是头节点
                if (cur == head) {
                    head = head.next;
                    //处理只有一个节点
                    if (head != null) {
                        head.prev = null;
                    }
                }else {
                    //中间 尾巴
                    cur.prev.next = cur.next;
                    //不是尾巴节点
                    if (cur.next != null) {
                        cur.next.prev = cur.prev;
                    }else {
                        //是尾巴节点
                        last = cur.prev;
                    }
                }
                return;
            }
            cur = cur.next;
        }
    }
    //删除所有值为key的节点 O(n)
    public void removeAllKey(int key){
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                //1.删除的是头节点
                if (cur == head) {
                    head = head.next;
                    //处理只有一个节点
                    if (head != null) {
                        head.prev = null;
                    }
                }else {
                    //中间 尾巴
                    cur.prev.next = cur.next;
                    //不是尾巴节点
                    if (cur.next != null) {
                        cur.next.prev = cur.prev;
                    }else {
                        //是尾巴节点
                        last = cur.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }
    //得到链表的长度
    public int size(){
        int len = 0;
        ListNode cur = head;
        while (cur != null) {
           len++;
            cur = cur.next;
        }
        return len;
    }
    //打印链表
    public void display(){
        ListNode cur = head;
        while (cur != null) {
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }
}   

总结: 
  不同点 ArrayList                 LinkedList
存储空间上物理上一定连续 逻辑上连续,但物理上不一定连续
随机访问       支持O(1)不支持:O(N)
头插 需要搬移元素,效率低O(N)    只需修改引用的指向,时间复杂度O(1)

插入

空间不够时需要扩容 没有扩容概念
应用场景元素高效存储+频繁问           任意位置插入和删除频繁

  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值