集合相关面试题

本文主要介绍了Java中Array和ArrayList的区别,包括大小是否固定、可包含的数据类型、方法特性等。还对比了ArrayList和LinkedList,涉及数据结构、插入删除复杂度、随机访问等方面。此外,阐述了JDK1.7前后LinkedList链表实现的变化及优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Array和ArrayList有什么区别?

  • Array大小是固定的,空间不够时也不能再次赛区,所以需要事前确定适合的空间大小;而ArrayList大小是动态变化的,它可以动态增长,如果空间不够,它会创建一个空间比原空间大约0.5倍的新数组,然后将所有元素复制到新数组中,接着抛弃旧数组,而且,每次添加新的元素都会检查内部数组的空间是否足够。
  • Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
  • ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
  • Array数组存放的时候一定是同种类型的元素,ArrayList就不一定了,因为ArrayList可以存储Object。

ArrayList和LinkedList有什么区别?

  • ArrayList是实现了基于动态Object数组的数据结构,LinkedList基于链表(双向链表)的数据结构。
  • 插入和删除是否受元素位置的影响: ① ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素 位置的影响。 比如:执行 add(E e) 方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话( add(int index, E element) )时 间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响,都是 近似 O(1)而数组为近似 O(n)。
  • ArrayList的底层是数组,它可以O(1)时间复杂度对元素进行随机访问;LinkedList是基于链表实现,查找元素的时间复杂度为O(n)。
  • LinkedList的插入,添加,删除操作速度更快,同时其内存消耗比ArrayList更多,因为LinkedList为每一个节点存储了两个引用。
  • ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全。

LinkedList链表优化
LinkedListList接口的双向链表实现。由于是链表结构,所以链表长度没有限制;添加、删除元素只需改变指针的指向即可,而ArrayList需要重整数组,所以LinkedList适用于添加、删除操作频繁的情况。

在JDK1.7前,LinkedList是通过headerEntry实现一个循环链表。先初始化一个空的Entry,用来做header,然后首尾相连,形成一个循环链表。
Node定义:

public class Node {
    public String content;
    public Node next;
    public Node previous;
    
    public Node(String content, Node next, Node previous) {
        this.content = content;
        this.next = next;
        this.previous = previous;
    }
}

循环链表实现:

public class ListNode_1 {
    public Node header = new Node(null, null, null);
    public int size = 0;


    //添加元素节点
    public void addNode(String content) {
        Node newNode = new Node(content, header, header.previous);
        header.previous.next = newNode;
        header.previous = newNode;
        size++;
    }

    public ListNode_1() {
        header.previous = header;
        header.next = header;
    }
}

在JDK1.7中headerEntry循环链表被替换成了first和last组成的非循环链表:

public class ListNode_2 {
    public Node first;
    public Node last;
    public int size = 0;

    public void addNode(String content) {
        Node index = last;
        Node newNode = new Node(content, null, index);
        last = newNode;
        if (first == null) {
            first = newNode;
        }else {
            index.next = newNode;
        }
        size++;
    }
}

JDK1.7中的first/last对比以前的header有以下好处:

  1. JDK1.7有更清晰的链头和链尾概念,代码容易理解明白。
  2. JDK1.7能节省new一个Header(实例化headerEntry是为了让后面的方法更加统一,否则会有许多Header的空校验)。
  3. 在链头尾进行插入/删除操作,JDK1.7方式更加快捷。(插入/删除操作分为中间和两头两种情况:
    在中间插入/删除,两者一样,都是先遍历找到index,然后修改index节点两边的指针(2个next,2个previou);在两头,则对于循环链表也是处理两边指针,而JDK1.7的非循环链表只需处理first或者last的一边指针(一个next,1个previous),所以理论上非循环链表更高效。实际操作中,链头和链尾操作最频繁。
    对于遍历,两者都是链表指针循环,所以遍历效果一样。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值