LinkedList浅析

LinkedList浅析LinkedList简介LinkedList是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。LinkedList实现List接口,能对它进行队列操作。LinkedList实现Deque接口,即能将LinkedList当作双端队列使用。LinkedList实现了Cloneable接口,即覆盖了函数clon…

大家好,又见面了,我是你们的朋友全栈君。


LinkedList是Collection下的一个list实现,就像ArrayList一样。

和ArrayList不同的是它是链表结构,而ArrayList是顺序结构。我们平常使用的list是一样的,理论上来说一种list就可以完成我们所有的需求。但是它们在运行过程中有区别的,完成需求所需要的资源也不相同,至于什么情况下使用哪种list就看需求和当前情况了。


视频:


LinkedList 是一个继承于AbstractSequentialList的双向链表
LinkedList 可以被当作堆栈、队列或双端队列进行操作。
LinkedList 实现 List 接口,所以能对它进行队列操作
LinkedList 实现 Deque 接口,能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,所以LinkedList支持序列化,能通过序列化去传输。
LinkedList 是非同步的。

java集合

构造函数

// 默认构造函数
LinkedList()

// 创建一个LinkedList,保护Collection中的全部元素。
LinkedList(Collection<? extends E> collection)

LinkedList的本质是双向链表

  1. LinkedList继承于AbstractSequentialList,并且实现了Dequeue接口。
  2. LinkedList包含两个重要的成员:header 和 size。
      header是双向链表的表头,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,previous是该节点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。
      size是双向链表中节点的个数。

##双向链表结构

  • 链表:链表是一种重要的数据结构,有单链表和双链表之分

单链表:

单链表(单向链表):由两部分组成 数据域(Data)和结点域(Node),单链表就像是一条打了很多结的绳子,每一个绳结相当于一个结点,每个节结点间都有绳子连接,这样原理的实现是通过Node结点区的头指针head实现的,每个结点都有一个指针,每个节点指针的指向都是指向自身结点的下一个结点,最后一个结点的head指向为null,这样一来就连成了上述所说绳子一样的链,对单链表的操作只能从一端开始,如果需要查找链表中的某一个结点,则需要从头开始进行遍历。

双向链表结构

双链表(双向链表):双链表和单链表相比,多了一个指向尾指针(tail),双链表的每个结点都有一个头指针head和尾指针tail,双链表相比单链表更容易操作,双链表结点的首结点的head指向为null,tail指向下一个节点的tail;尾结点的head指向前一个结点的head,tail 指向为null,是双向的关系;
在单链表中若需要查找某一个元素时,都必须从第一个元素开始进行查找,而双向链表除开头节点和最后一个节点外每个节点中储存有两个指针,这连个指针分别指向前一个节点的地址和后一个节点的地址,这样无论通过那个节点都能够寻找到其他的节点。

  • 插入删除不需要移动元素外,可以原地插入删除
  • 可以在结构的前后插入数据
  • 可以双向遍历

###链表


AbstractSequentialList

Linklist是AbstractSequentialList的子类

AbstractSequentialList 实现了get(int index)、set(int index, E element)、add(int index, E element) 和 remove(int index)这些函数。这些接口都是随机访问List的,LinkedList是双向链表;既然它继承于AbstractSequentialList,就相当于已经实现了“get(int index)这些接口”。
此外,我们若需要通过AbstractSequentialList自己实现一个列表,只需要扩展此类,并提供 listIterator() 和 size() 方法的实现即可。若要实现不可修改的列表,则需要实现列表迭代器的 hasNext、next、hasPrevious、previous 和 index 方法即可。

LinkedList的继承关系:

java.lang.Object
   ↳ java.util.AbstractCollection<E>
         ↳ java.util.AbstractList<E>
               ↳ java.util.AbstractSequentialList<E>
                     ↳  java.util.LinkedList<E>

    public class LinkedList<E>
         extends AbstractSequentialList<E>
            implements List<E>, Deque<E>, Cloneable, java.io.Serializable { …… }

LinkedList与Collection关系

Collection:

Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。

LinkedList浅析


LinkedList的本质是双链表,实现 List 和 Deque接口:

LinkedList浅析

在LinkedList中,每个节点都用内部类Node表示:

LinkedList浅析

具体的过程可以看下面这张图:
点我

每个node都是节点,里面有三个属性,分别指向上一个节点、下一个节点、实际储存元素开辟的内存空间

而对linkedlist里元素的操作方法都是对这些节点进行操作:

add()操作:

 /**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #addLast}.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

  /**
     * Links e as last element.
     */
    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

remove()操作

    /**
     * Removes the element at the specified position in this list.  Shifts any
     * subsequent elements to the left (subtracts one from their indices).
     * Returns the element that was removed from the list.
     *
     * @param index the index of the element to be removed
     * @return the element previously at the specified position
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

	//查找对应索引
    private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * Unlinks non-null node x.
     */
    E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        modCount++;
        return element;
    }


可以看到都是对node节点进行操作,真实的实例内存并没有任何改变,等着jvm回收。


List使用场景

ArrayList在随机访问方面比较擅长,LinkedList在随机增删方面比较擅长
对于需要快速插入,删除元素,使用LinkedList。因为ArrayList要想在数组中任意两个元素中间添加对象时,数组需要移动所有后面的对象。
对于需要快速随机访问元素(get()),应该使用ArrayList,因为LinkedList要移动指针、遍历节点来定位,所以速度慢。
对于“单线程环境” 或者 “多线程环境,但List仅仅只会被单个线程操作”,此时应该使用非同步的类(如ArrayList)。
对于“多线程环境,且List可能同时被多个线程操作”,此时,应该使用同步的类(如Vector)。

对于插入数据使用时间的对比:

  public static void addTest(){

        //批量插入,每次都向首位插入数据;

        LinkedList linkedList = new LinkedList();

        long time1 = new Date().getTime();

        for(int m=0;m<300000;m++){
            linkedList.add(0,null);
        }

        long time2 = new Date().getTime();

        System.out.print("linkedList批量插入时间:"+(time2 - time1)+"ms\n");




        ArrayList arraylist = new ArrayList();

        long time3 = new Date().getTime();

        for(int n=0;n<300000;n++){
            arraylist.add(0, null);
        }

        long time4 = new Date().getTime();
        System.out.print("arrayList批量插入时间:"+(time4 - time3)+"ms\n");

    }

结果:

linkedList批量插入时间:9ms
arrayList批量插入时间:3696ms


那么问题就来了:

Q:什么时候使用Arraylist,什么时候使用LinkedList?
A:当你需要频繁查询数组的时候使用ArrayList比较快,当你需要频繁操作数组进行增删插入操作的时候使用LinkList比较合适。当然直接在末尾添加数据ArrayList用时也不是特别多,因为在末尾操作后面没有数据。

Q:那什么时候适合用list呢
A:涉及到“栈”、“队列”、“链表”等操作,应该考虑用List,具体的选择哪个List,根据下面的标准来取舍

  • 对于需要快速插入,删除元素,应该使用LinkedList。
  • 对于需要快速随机访问元素,应该使用ArrayList。
  • 对于“单线程环境” 或者 “多线程环境,但List仅仅只会被单个线程操作”,此时应该使用非同步的类(如ArrayList)。
  • 对于“多线程环境,且List可能同时被多个线程操作”,此时,应该使用同步的类(如Vector)。

Q:线程安全的数组,什么是线程安全?
A:线程安全就是当前资源只能被单独一个线程访问,也就是加同步锁的线程。默认的线程安全的list是Vector;


以上,如果有哪里不对或者不清楚的地方欢迎勾搭,多谢指正

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/148212.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ssm框架整合步骤_bootstrap框架搭建

    ssm框架整合步骤_bootstrap框架搭建描述普通情况下,控制台打印出的sql是带?的,开发人员在自己调试的过程中遇到bug是再常见不过了,如果想看一下程序打出来的sql,发现参数的位置都是?,是不是很不爽,若想在数据库中执行sql,还需要手动修改sql的参数,真是麻烦,使用p6spy可以将sql格式化然后打出,打出的sql不再是带有?的,而是可以直接拷贝到数据库执行的。整合步骤如下:添加jar包依赖在service层…

    2022年10月5日
    3
  • native/ascii在线转换工具_中文转ascii

    native/ascii在线转换工具_中文转ascii1,原理Property文件中,使用的编码根据机器的设置可能是GBK或者UTF-8。而在Java中读取Property文件时使用的是Unicode编码,编码方式不同会导致中文乱码,因此需要将Property文件中的中文字符转化成Unicode编码才能正常显示中文。2,解决办法Java提供了native2ascii这种专门的工具对Property文件进行编码转换,在JDK安装环境的bin目录下可以找…

    2022年9月11日
    2
  • 几种常见的Runtime Exception

    几种常见的Runtime Exception摘要:一,error和exception的区别,RuntimeException和非RuntimeException的区别1.异常机制异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提

    2022年7月1日
    23
  • SOA到底是什么

    SOA到底是什么SOA到底是什么 首先,SOA是一种开发思想。是一种松耦合的框架。可以让软件超越开发语言。SOA强调的是一种架构思想,组件化的灵活的开发方式。SOA是一场革命。一个应用程序的业务逻辑(businesslogic)或某些单独的功能被模块化并作为服务呈现给消费者或客户端。这些服务的关键是他们的松耦合特性。例如,服务的接口和实现相独立。应用开发人员或者系统集成者可以通过组合一个或多个服务来…

    2022年6月17日
    28
  • 网页中的表单设计(网页表单制作步骤)

    在学习了最基本的网页元素后,接触到了表单,下面是用HTML写的很基础的表单,中间设计到了一点点CSS的内容,不算复杂。<!doctypehtml><html><head><metacharset=”utf-8″><title>表单综合实例</title><styletype=”text/css”&g…

    2022年4月18日
    89
  • IDEA卸载

    IDEA卸载第一步:打开文件安装目录,点击1,鼠标右击【属性】,再点击打开文件安装位置。第二步:在打开的文件夹里面。找到【Uninstall.exe】这一选项。操作参照我在图中标注,双击使其正常运行启动。第三步:卸载过程的弹出框确认,是否需要删除一些配置和历史记录。第四步:就是确认前面的设置之后,然后就静静的等待进度条完成即可。第五步:删除的内容可以关注下,很多的删除了C盘的…

    2022年6月14日
    1.7K

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号