LinkedList源码解析一

本文介绍了ArrayList和LinkedList两种数据结构。ArrayList是动态数组集合,查询快但增删慢、扩容浪费内存;LinkedList是双向链表,可按需申请内存,增删快但查询慢。还阐述了链表分类、概念,以及实现单向链表和LinkedList部分方法,提及可达性算法判断对象是否为垃圾。

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

我们都知道ArrayList称为动态数组集合,所谓的动态数组,并不是说数组的大小可以发生改变,我们都知道,在创建数组的时候都需要指定数组的长度,一旦数组创建,数组的长度是不能改变的。

那么ArrayList是如何实现动态数组的方式呢,可以看之前的文章ArrayList源码分析一,概括来说就是调用ArrayList在Add方法进行元素添加的时候,会判断能不能装下新添加的元素,如果能放下就放到数组里面去,如果放不下,ArrayList就会新开辟一个数组,同时将原数组里面的数据拷贝到新数组里面去,同时把添加的元素放到新数组的最后一位。

ArrayList有数组的优点和缺点,优点是有索引,查询比较快。缺点是增删慢和扩容的时候比较浪费内存空间。

LinkedList可以克服这些缺点,LinkedList的内存空间可以用到多少就申请多少以及LinkedList的增删比较快。

链表的分类

单链表、 双链表和循环链表。

链表的概念

链表是由链将每一个Node进行连接,Node里面放的是我们添加的元素。

Node节点里面有2个数据,一个是存放我们存的数据值。另一个是存放下一个节点的内存地址。需要注意的是,Node元素是不连续的,也就是链表的数据结构也不是连续的。每次添加都是new出来的,所以不是连续的。

链表是可以实现用到多少内存空间就申请多少空间的并且又能够提高增删速度。

链表如此优秀,为什么还要用数组这种数据结构呢?

由于链表的内存不连续,没有索引的概念,所以链表的查询比较慢。链表的查询是通过遍历的方式,多以比较慢。

LinkedList本身是个双向链表。

我们先来实现一个单向链表:

/**
 * description:将ArrayList和LinkedList里面的共性方法进行抽取
 */
public interface List<E> {
    int size();

    boolean isEmpty();

    boolean contains(E element);

    void add(E element);

    E get(int index);

    E set(int index, E element);

    void add(int index, E element);

    E remove(int index);

    int indexOf(E element);

    void clear();

    String toString();
}
/**
 * description:实现ArrayList和LinkedList的共性方法
 */
public abstract class AbstractList<E> implements List<E> {
    protected int size;

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean contains(E element) {
        return indexOf(element) != -1;
    }
}

在Node节点里面有2个数据,一个是存放我们存的数据值。另一个是存放下一个节点的内存地址。在LinkedList里面定一个内部类Node来实现这个Node:

    private static class Node<E> {
        Node<E> next;
        E element;

        public Node(Node<E> next, E element) {
            this.next = next;
            this.element = element;
        }
    }

 LinkedList的结构如下:

package com.example.suanfademo;

class MyLinkedList<E> extends AbstractList<E> {
    
    private Node first;

    private static class Node<E> {
        Node<E> next;
        E element;

        public Node(Node<E> next, E element) {
            this.next = next;
            this.element = element;
        }
    }

    @Override
    public void add(E element) {
        
    }

    @Override
    public E get(int index) {
        return null;
    }

    @Override
    public E set(int index, E element) {
        return null;
    }

    @Override
    public void add(int index, E element) {

    }

    @Override
    public E remove(int index) {
        return null;
    }

    @Override
    public int indexOf(E element) {
        return 0;
    }

    @Override
    public void clear() {

    }
}

 实现 LinkedList的get方法:

    @Override
    public E get(int index) {
        checkElementIndex(index);
        return node(index).element;
    }

    private void checkElementIndex(int index) {
        if (!isElementIndext(index)) {
            throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
        }
    }

    private boolean isElementIndext(int index) {
        return index >= 0 && index < size;
    }

    private Node<E> node(int index) {
        Node x = first;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        return x;
    }

 实现 LinkedList的set方法:

    @Override
    public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> node = node(index);
        E oldValue = node.element;
        node.element = element;
        return oldValue;
    }
    

实现 LinkedList的clear方法:可达性算法:判断一个对象是一个垃圾的标准 选取一个节点作为GC Roots的顶点,其他对象或者引用指向这个GC Roots的顶点,如果这个对象能够到达这个GC Roots顶点的,那么这些对象就不是垃圾,反之就会被认为是null

    @Override
    public void clear() {
        size = 0;
        first = null;
    }

  实现 LinkedList的indexOf方法:

    @Override
    public int indexOf(E element) {
        Node x = this.first;
        if (element == null) {
            for (int i = 0; i < size; i++) {
                if (x.element == null) {
                    return i;
                }
                x = x.next;
            }

        } else {
            for (int i = 0; i < size; i++) {
                if (element.equals(x.element)) {
                    return i;
                }
                x = x.next;
            }
        }

        return -1;
    }

   实现 LinkedList的add方法:

    @Override
    public void add(int index, E element) {
        checkPositionIndex(index);
        //add(0,100)的情况
        if(index == 0){
            first = new Node<E>(first, element);
        }else{
            //要获取前一个Node和后一个Node,改变他们的指向
            Node<E> pre = node(index - 1);
            Node<E> next = pre.next;
            Node<E> newNode = new Node<E>(next,element);
            pre.next = newNode;
        }
        size++;
    }

    实现 LinkedList的toString方法:

    @Override
    public String toString() {
        if (size == 0) {
            return "[]";
        }

        Node x = first;
        StringBuilder stringBuilder = new StringBuilder().append("[");
        for (int i = 0; i < size; i++) {
            if (i != size - 1) {
                stringBuilder.append(x.element).append(",").toString();
            } else {
                stringBuilder.append(x.element).append("]").toString();
            }
            x = x.next;
        }

        return stringBuilder.toString();
    }

   实现 LinkedList的remove方法:

    @Override
    public E remove(int index) {
        checkElementIndex(index);
        Node<E> oldValue = first;
        if (index == 0) {
            oldValue = first;
            first = first.next;
        } else {
            //index的前一个节点
            Node<E> pre = node(index - 1);
            //index的后一个节点
            Node<E> next = pre.next.next;
            oldValue = pre.next;

            pre.next = next;
        }
        return oldValue.element;
    }
package com.example.suanfademo;

/**
 * *******************************************
 * Create by Jingjing.Lin2
 * 2020/10/20 20:15
 * description:
 * ******************************************
 */
class MyLinkedList<E> extends AbstractList<E> {

    private Node first;//头节点

    private static class Node<E> {
        Node<E> next;
        E element;

        public Node(Node<E> next, E element) {
            this.next = next;
            this.element = element;
        }
    }

    @Override
    public void add(E element) {
        add(size, element);
    }

    @Override
    public E get(int index) {
        checkElementIndex(index);
        return node(index).element;
    }

    private void checkElementIndex(int index) {
        if (!isElementIndext(index)) {
            throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
        }
    }

    private boolean isElementIndext(int index) {
        return index >= 0 && index < size;
    }

    private Node<E> node(int index) {
        Node x = first;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        return x;
    }


    @Override
    public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> node = node(index);
        E oldValue = node.element;
        node.element = element;
        return oldValue;
    }

    @Override
    public void add(int index, E element) {
        checkPositionIndex(index);
        //add(0,100)的情况
        if (index == 0) {
            first = new Node<E>(first, element);
        } else {
            //要获取前一个Node和后一个Node,改变他们的指向
            Node<E> pre = node(index - 1);
            Node<E> next = pre.next;
            Node<E> newNode = new Node<E>(next, element);
            pre.next = newNode;
        }
        size++;
    }

    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index)) {
            throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
        }
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

    @Override
    public E remove(int index) {
        checkElementIndex(index);
        Node<E> oldValue = first;
        if (index == 0) {
            oldValue = first;
            first = first.next;
        } else {
            //index的前一个节点
            Node<E> pre = node(index - 1);
            //index的后一个节点
            Node<E> next = pre.next.next;
            oldValue = pre.next;

            pre.next = next;
        }
        return oldValue.element;
    }


    @Override
    public int indexOf(E element) {
        Node x = this.first;
        if (element == null) {
            for (int i = 0; i < size; i++) {
                if (x.element == null) {
                    return i;
                }
                x = x.next;
            }

        } else {
            for (int i = 0; i < size; i++) {
                if (element.equals(x.element)) {
                    return i;
                }
                x = x.next;
            }
        }

        return -1;
    }

    /**
     * 可达性算法:判断一个对象是一个垃圾的标准
     * 选取一个节点作为GC Roots的顶点,其他对象或者引用指向这个GC Roots的顶点,如果这个对象能够到达这个GC Roots顶点的,那么这些对象就不是垃圾,反之就会被认为是null
     */
    @Override
    public void clear() {
        size = 0;
        first = null;
    }

    @Override
    public String toString() {
        if (size == 0) {
            return "[]";
        }

        Node x = first;
        StringBuilder stringBuilder = new StringBuilder().append("[");
        for (int i = 0; i < size; i++) {
            if (i != size - 1) {
                stringBuilder.append(x.element).append(",").toString();
            } else {
                stringBuilder.append(x.element).append("]").toString();
            }
            x = x.next;
        }

        return stringBuilder.toString();
    }
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值