LinkedList的方法分析
来源:互联网 发布:杭州程序员招聘信息 编辑:程序博客网 时间:2024/04/28 08:37
可以看出来LinkedList不仅实现了List接口,还实现了Deque(双端队列),这使得LinkedList可以实现队列的一些特性
// 成员变量:header是一个entry实例,既然知道linkedlist是实现了链表结构,header// 显然是头结点,而且可以看出来,header并不用于存放元素,而是为其他元素提供一个初始// 位置private transient Entry<E> header = new Entry<E>(null, null, null);// size指当前链表中节点个数,不包括头结点private transient int size = 0;....// entry静态内部类private static class Entry<E> { // 当前节点自身的内容 E element; // 后一个节点的引用 Entry<E> next; // 前一个节点的引用 Entry<E> previous; // 第一个参数,第二个参数是next,第三个是previous,顺序要记住 Entry(E element, Entry<E> next, Entry<E> previous) { this.element = element; this.next = next; this.previous = previous; }}// 头结点的前一个节点指向自身,后一个节点也指向自身,由这个空链表也可以看出来LinkedList是一个双向循环// 链表public LinkedList() { header.next = header.previous = header;}// 把集合转化成LinkedListpublic LinkedList(Collection<? extends E> c) { // 仍然首先定义一个空链表 this(); addAll(c);}
public boolean addAll(Collection<? extends E> c) { // 在size处插入集合元素 return addAll(size, c);}// index,从链表的index处(在index-1和index之间)开始插入给定的集合public boolean addAll(int index, Collection<? extends E> c) { // 如果index为负数或者index大于链表中节点个数,抛出异常 if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+size); // 集合转数组,如果数组长度为0(集合元素为空),返回false Object[] a = c.toArray(); int numNew = a.length; if (numNew==0) return false; // 结构变化指标+1 modCount++;// 如果index=size,就在header前插入,如果不是就在index对应的元素前插入// successor是待插入的位置后的节点Entry<E> successor = (index==size ? header : entry(index));// 获得带插入位置的前一个节点,保存predecessor Entry<E> predecessor = successor.previous;// 遍历集合元素 for (int i=0; i<numNew; i++) { // new一个新的entry,也就是带插入的节点,next为刚刚得到插入位置后的,previous是插入位置前的 // 这个new节点的步骤,实际上完成了插入节点本身前后两个属性引用的指向,也就是说到这个步骤为止 // 根据这个节点可以找到整个链表的元素,但是根据链表的其他节点还不能找到这个新插入的节点,因为和 // 它相邻的节点的next,previous的指向还没有改 Entry<E> e = new Entry<E>((E)a[i], successor, predecessor); // 前一个节点的next指向新插入的节点,插入完成了2/3 predecessor.next = e; // 把新插入的节点作为下一个带插入的节点的前一个节点,循环 predecessor = e;}// 循环结束,实际上这时候所有的集合元素,除了最后一个,都已经首尾相连,最后一个元素自身也已经指向原链表的// index处的节点// 插入工作的最后一步,index处的节点,previous引用指向集合的最后一个节点successor.previous = predecessor; // size加上集合长度 size += numNew; return true;}
// add方法,试图在linkedlist尾部插入一个元素public boolean add(E e) { addBefore(e, header); return true; }============================= // 在给定index之前插入一个元素 public void add(int index, E element) { // 如果index=size,那么和直接add到链表末尾一样,调用addbefore插入到header之前 // 如果不是size,调用entry()返回带插入位置的当前节点 addBefore(element, (index==size ? header :entry(index))); }============================== // 在给定参数entry节点前插入一个元素,对于header来说,header.previous // 就是链表的最后一个,这也说明了linkedlist实现了一个双向循环链表 private Entry<E> addBefore(E e, Entry<E> entry) { // 构成一个新的节点,previous是entry.previous,next是entry // 对于header来说,新节点已经插入了last和header之间(仅其自身引用指向改变) Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); // newEntry.previous就是新节点的前一个节点,但是它的next引用目前仍然 // 指向newEntry.next,所以修改之,下面同理。 newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; // 节点数+1,结构变化+1,返回新插入的entry size++; modCount++; return newEntry;}
可以看出来add方法调用addbefore完成了在header之前,也就是链表末尾的插入工作。
get(int index)和addBefore(E e, Entry entry)都用到了entry(int index)方法,这个方法实际上是根据index对链表遍历返回对应的节点
public E get(int index) { return entry(index).element; }
private Entry<E> entry(int index) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+size); // header保存在局部变量e Entry<E> e = header; // 判断index在链表中的位置,跟size/2比较,决定是从前往后遍历还 // 是从后往前遍历 if (index < (size >> 1)) { for (int i = 0; i <= index; i++) e = e.next; } else { for (int i = size; i > index; i--) e = e.previous; } return e; }
// 从linkedlist中删除某个元素 public boolean remove(Object o) { // 这里把非空作为分支条件主要是因为o.equals(),会空指针异常 if (o==null) { // 从header往后遍历,如果为空(e.element==null),就删除该节点 for (Entry<E> e = header.next; e != header; e = e.next) { if (e.element==null) { remove(e); return true; } } } else { for (Entry<E> e = header.next; e != header; e = e.next) { // 如果element和给定的元素equals返回true,则删除该节点 if (o.equals(e.element)) { remove(e); return true; } } } return false; }===================================private E remove(Entry<E> e) {// header不能删除 if (e == header) throw new NoSuchElementException();// 把要删除的元素(不是节点),作为删除方法的返回值 E result = e.element;// 修改其头尾节点的next和previous指向,跳过待删除的节点 e.previous.next = e.next; e.next.previous = e.previous; // 把删除的节点各个引用属性都改为null,等待gc回收 e.next = e.previous = null; e.element = null; // size--; modCount++; return result; }
0 0
- LinkedList的方法分析
- LinkedList的源码分析
- LinkedList的源码分析
- LinkedList源代码的分析
- LinkedList的源码分析
- LinkedList的源码分析
- 测试LinkedList的方法
- LinkedList的delete方法
- LinkedList的索引方法
- linkedList特有的方法
- LinkedList的实现原理分析
- LinkedList分析
- LinkedList分析
- LinkedList分析
- ArrayList和LinkedList的源码分析
- JDK中LinkedList的实现分析
- Array, ArrayList, LinkedList之间的区别分析
- ArrayList和LinkedList add的源码分析
- CSS清除浮动方法集合
- Android 屏幕适配扫盲、教程
- Serial Chart软件使用说明
- LeetCode #11 Container With Most Water
- org.springframework.beans.factory.BeanCreationException: Error creating bean 
- LinkedList的方法分析
- IntelliJ IDEA使用技巧
- 时频特性分析(Matlab)
- lintcode——链表倒数第n个节点
- 部署图
- cccc L2-020. 功夫传人
- Java基础之加解密(四) 对称加密算法使用
- 续三,用RecyclerView来实现苹果后台样式的卡片布局
- 【测试】测试用例检查清单