LinkedList源码分析

1.概述

高效插入和删除的有序序列
线程不安全,非同步
数据结构:链表(双向链表)
继承了AbstractSequentialList,可以作为栈和队列使用
实现了Deque,可以做双向链表
遍历时推荐使用iterater

关系图:

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

LinkedList

2.源码
常用属性:
// 元素个数
transient int size = 0;
// 头节点
transient Node<E> first;
//尾节点
transient Node<E> last;


// 记录修改次数,与线程有关的属性(平时使用并不多)
protected transient int modCount = 0;
常用构造方法:
// 默认构造方法
public LinkedList() {}

// 指定添加元素,并不常用
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}
核心内部类:
/**
 * 链表的数据结构
 */
private static class Node<E> {
    E item;         // 数据域
    Node<E> next;   // 下一个结点
    Node<E> prev;   // 上一个结点

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}
/**
 * 主要与LinkedList的迭代有关
 * 而且在迭代的过程中能对元素进行操作
 */
private class ListItr implements ListIterator<E> {
    private Node<E> lastReturned = null;
    private Node<E> next;
    private int nextIndex;
    private int expectedModCount = modCount;
    
    // methods()....
}
核心方法:
/**
 * 添加元素到链表尾部
 */
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++;
}
// ---------

重点看一下删除元素的过程

/**
 * Removes the first occurrence of the specified element from this list
 * 移除链表第一个匹配的元素
 */
public boolean remove(Object o) {
    // 遍历链表,找到符合的结点,再使用unlink真正移除该结点
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    // 没找到则返回 false
    return false;
}

/**
 * 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;

    // 移除头结点,头结点改变成头结点的next
    if (prev == null) {
        first = next;
    } else {
        // 移除中间结点的一半引用(指针)操作(这个操作自己画一张图看起来更加直观)
        prev.next = next;
        x.prev = null;
    }

    // 移除尾结点,尾结点改变为尾结点的pre
    if (next == null) {
        last = prev;
    } else {
        // 移除中间结点的另一半引用(指针)操作
        next.prev = prev;
        x.next = null;
    }

    // 前面的prev和next的引用都清除了,现在清楚数据域的引用
    x.item = null;
    size--;
    modCount++;
    return element;
}

上面这些方法中,重点学习unlinck(),在指定位置插入也是相似的。

参考

Java集合源码分析(二)Linkedlist
原文:LinkedList源码分析

可以看一下我用Java写的线性表的链式实现

Stkcd [股票代码] ShortName [股票简称] Accper [统计截止日期] Typrep [报表类型编码] Indcd [行业代码] Indnme [行业名称] Source [公告来源] F060101B [净利润现金净含量] F060101C [净利润现金净含量TTM] F060201B [营业收入现金含量] F060201C [营业收入现金含量TTM] F060301B [营业收入现金净含量] F060301C [营业收入现金净含量TTM] F060401B [营业利润现金净含量] F060401C [营业利润现金净含量TTM] F060901B [筹资活动债权人现金净流量] F060901C [筹资活动债权人现金净流量TTM] F061001B [筹资活动股东现金净流量] F061001C [筹资活动股东现金净流量TTM] F061201B [折旧摊销] F061201C [折旧摊销TTM] F061301B [公司现金流1] F061302B [公司现金流2] F061301C [公司现金流TTM1] F061302C [公司现金流TTM2] F061401B [股权现金流1] F061402B [股权现金流2] F061401C [股权现金流TTM1] F061402C [股权现金流TTM2] F061501B [公司自由现金流(原有)] F061601B [股权自由现金流(原有)] F061701B [全部现金回收率] F061801B [营运指数] F061901B [资本支出与折旧摊销比] F062001B [现金适合比率] F062101B [现金再投资比率] F062201B [现金满足投资比率] F062301B [股权自由现金流] F062401B [企业自由现金流] Indcd1 [行业代码1] Indnme1 [行业名称1] 季度数据,所有沪深北上市公司的 分别包含excel、dta数据文件格式及其说明,便于不同软件工具对数据的分析应用 数据来源:基于上市公司年报及公告数据整理,或相关证券交易所、各部委、省、市数据 数据范围:基于沪深北证上市公司 A股(主板、中小企业板、创业板、科创板等)数据整理计算
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值