互联网架构-Java8集合框架源码分析-039:LinkedList集合源码深度解析

1 LinkedList底层链表数据结构分析

课程内容:
1、LinkedList与ArrayList区别
2、数据结构之链表与数组区别
3、完全白话文分析LinkedList
4、纯手写LinkeList链表数据结构

算法的时间复杂度和空间复杂度
时间复杂度指的就是一个算法执行所耗费的时间;
空间复杂度指的就是一个算法所耗费的存储空间;

数组与链表数据结构区别
数组查询效率比较高(使用下标定位元素),但是增删效率比较低(多个元素移动);
链表查询效率比较低(范围查询),但是增删效率比较高(改变节点头尾指向);

2 手写简单版本LinkedList实现基本功能

public interface MayiktList<E> {
    /**
     * 集合大小
     * @return
     */
    int size();

    /**
     * 添加元素
     * @param e
     * @return
     */
    boolean add(E e);

    /**
     * 使用下标查询元素
     * @param index
     * @return
     */
    E get(int index);

    /**
     * 使用下标删除元素
     * @param index
     * @return
     */
    public E remove(int index);
}
public class MayiktLinkedList<E> implements MayiktList<E> {

    /**
     * 集合大小
     */
    transient int size = 0;

    transient MayiktLinkedList.Node<E> first;

    transient MayiktLinkedList.Node<E> last;

    public int size() {
        return size;
    }

    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    public void linkLast(E e) {
        // 获取当前最后的元素节点
        final MayiktLinkedList.Node<E> l = last;
        // 设置新增的node节点元素
        final MayiktLinkedList.Node<E> newNode = new MayiktLinkedList.Node<E>(l, e, null);
        // 将新增的节点设为最后节点
        last = newNode;
        if (l == null) {
            // 说明当前链表第一次添加元素
            first = newNode;
        } else {
            l.next = newNode;
        }
        size++;
    }

    public E get(int index) {
        // 检查数组是否越界
        checkElementIndex(index);
        return (E) node(index).item;
    }

    MayiktLinkedList.Node<E> node(int index) {
        // 折半查找
        if (index < (size >> 1)) {
            // 获取第一个节点
            MayiktLinkedList.Node<E> x = first;
            // 从0开始到当前下标位置
            for (int i = 0; i < index; i++) {
                // 获取下一个节点
                x = x.next;
            }
            return x;
        } else {
            // 获取最后一个节点
            MayiktLinkedList.Node<E> x = last;
            // 从最后一个元素开始向前遍历
            for (int i = size - 1; i > index; i--) {
                x = x.prev;
            }
            return x;
        }
    }

    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

    E unlink(MayiktLinkedList.Node<E> x) {
        // 获取当前删除节点的内容
        E item = x.item;
        // 获取当前删除节点的下一个节点
        Node<E> next = x.next;
        // 获取当前删除节点的上一个节点
        Node<E> prev = x.prev;
        if (prev == null) {
            // 删除节点为头结点
            first = next;
        } else {
            // 上一个节点的next 指向 当前删除节点的next
            prev.next = next;
            // 删除节点的上节点变为空,告诉gc回收
            x.prev = null;
        }
        if (next == null) {
            // 当前删除节点为尾节点
            last = prev;
        } else {
            // 下一个节点的prev 指向 当前节点的prev
            next.prev = prev;
            // 删除节点的下节点变为空,告诉gc回收
            x.next = null;
        }
        x.item = null;
        size--;
        return item;
    }
    
    // 链表中的节点
    private static class Node<E> {
        /**
         * 节点元素值
         */
        E item;

        /**
         * 当前节点的下一个Node
         */
        MayiktLinkedList.Node<E> next;
        /**
         * 当前节点上一个Node
         */
        MayiktLinkedList.Node<E> prev;

        // 使用构造函数传递参数
        Node(MayiktLinkedList.Node<E> prev, E element, MayiktLinkedList.Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }

    }

    private void checkElementIndex(int index) {
        if (!isElementIndex(index)) {
            throw new IndexOutOfBoundsException("index越界...");
        }
    }

    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }
}
public class Test {
    public static void main(String[] args) {
        MayiktLinkedList<String> stringMayiktLinkedList = new MayiktLinkedList<String>();
        stringMayiktLinkedList.add("mayikt1");
        stringMayiktLinkedList.add("mayikt2");
        stringMayiktLinkedList.add("mayikt3");
        System.out.println(stringMayiktLinkedList.get(1)); //mayikt2
        stringMayiktLinkedList.remove(1);
        System.out.println(stringMayiktLinkedList.get(1)); //mayikt3
    }
}

3 LinkedList底层源码分析完全总结

链表数据底层原理实现:双向链表头尾相接

  1. 在底层中使用静态内部类Node节点存放节点元素
    三个属性:prev 上一个节点、item 当前的值、next 下一个节点
  2. Add原理:一直在链表之后新增;
  3. Get原理:链表查询效率非常低, linkeList中采用折半查找,范围查询定位node节点;
  4. Remove原理:改变头尾相结合,改变指向;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值