LinkedList源代码阅读

LinkedList是一个基于双向链表的数据结构,它的插入和删除操作高效,但查找效率较低。构造方法包括无参和带参,后者会从集合中添加元素。add方法主要调用linkLast将元素添加至链表尾部。删除和获取元素涉及unlink和遍历操作,modCount用于迭代器的并发控制。
摘要由CSDN通过智能技术生成

LinkedList的底层是基于双向链表实现的,所以插入和删除效率较高,但是不易查找(因为链表在内存中存放的地址是不连续的)。 


 LInkedList中数据的个数。


头节点。 


尾节点 


构造方法:

一个无参构造方法,一个有参构造方法。有参构造方法传入一个集合,在这个方法体内部可以看到先调用了无参构造方法,然后使用addAll()方法将集合的数据添加到链表中。 


添加元素

add()

 add方法体内部只调用了linkLast()方法。linkLast()方法如下。


 linkLast()

(这里有些啰嗦,但是很清晰,后面的头插法可以参考这里的解释自己理解更加深刻)

linkLast()方法就是将数据插入到链表的尾部。

创建一个新的节点类对象 l 存放当前链表的尾节点last,

创建一个新的节点类对象 newNode 存放传进的元素e,将它的前一个节点设置为原链表的尾节点,将它的后继节点设置为null就行,再让last指向传进来的节点newNode。

判断语句就是判断这个链表是否为空,为空的话此时传进去要尾插的元素就是第一个,也就是说它既是这个链表的头节点也是尾节点,让first指向它,不为空就是原来链表的后继节点,让原来链表的最后一个元素的next指向它。

最后让链表的元素个数加1,对链表的操作次数加1。

 补充一下:

上面提到了modCount

记录对 List 操作的次数,主要使用是在 Iterator,是防止在迭代的过程中集合被修改。该变量定义在AbstractList中,被ArrayList继承。思考一下,如果我们在遍历集合时,对集合进行了修改,比如说删除了某一个元素,那么很容易导致结果出错或者下标越界。


linkFirst(),linkBefore() 

 linkFirst这段代码大家根据我上面说的linkLast自己服用吧。

这里linkBefore多说一嘴,可以看到传进的参数多了一个succ节点,这个节点就是存进去的e。succ.prev就是找到它的前驱节点。剩下代码请亲们自己服用。


add(int index, E element)

首先检查数组插入位置是否越界,调用checkPositionIndex(index)方法,若越界则抛出异常。判断插入的位置是否是尾部,如果是尾部直接调用 linkLast 方法,若不是则调用 linkBefore 方法。而 linkLast 方法已经在上文分析过了。 值得注意的是,对于插入位置是头结点的情况,LinkBefore 方法中进行了判断。


addAll() 

 首先检查要添加的位置是否越界,

将要插入的集合转型为Object[]数组,

判断数组不为空再进行下面的代码。

 Node<E> pred, succ; // 用于添加操作的两个临时的指针
 if (index == size) { //确定你的插入位置是否在末尾
    succ = null;
    pred = last;
 } else {
 succ = node(index); //当你的插入位置不在末尾时,node方法用于确定你指定位置的节点。
 pred = succ.prev; // 将指定节点的前向指针赋值给pred
 }

这里提到了node(index)方法,我们下面看看他是怎么找到插入位置元素的。

对index 进行了比较,如果小于 size 的一半(size >> 1 右移一位,相当于除2),那么是从头往后查找元素,否则从尾部往前查找元素。然后返回这个元素。 

for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }

pred存放的是前一个节点的地址 ,for循环将元素依次插入。

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

判断插入元素是否在末尾,将节点进行连接。


删除元素

remove(int index)

 

unlink是删除这个节点

移除第一个元素,这里将 item 和 next 置空是让垃圾回收器回收这部分内存。

removeFirst(),removeLast(),clear()可以参考remove(int index)。


获取元素

get(int index)

 这里要遍历数组来获取对应下标位置的信息,所以其查找效率比较低。

getFirst(),getLast() 

 直接获取首位元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值