深入理解LinkedList
来源:互联网 发布:唯美画面知乎 编辑:程序博客网 时间:2024/06/07 05:32
说明
本文是基于JDK7对LinkedList进行总结。通过阅读源码,对LinkedList的实现原理,特点等进行理解和掌握。
正文
LinkedList的特点
与ArrayList不同的是,LinkedList是基于双向链表实现的,适合增删多查找少的场景;相同的是都允许有空值(null),允许有重复值,插入数据是有序的,都是非线程安全的。
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
LinkedList继承了AbstractSequentialList类,实现了List, Deque, Cloneable, java.io.Serializable接口。
除了可以当作链表操作外,还可以当作栈、队列或双端队列使用。
节点类Node
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的成员变量
transient int size = 0;//链表中节点的个数transient Node<E> first;//首节点transient Node<E> last;//尾节点
LinkedList的构造函数
缺省构造函数
public LinkedList() { }//方法为空
指定一个Collection对象作为参数的构造函数,元素的顺序有这个对象迭代器返回的顺序决定
public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
链表中的插入
LinkedList的linkFirst(E e)方法
在链头插入一个元素
private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f); first = newNode; if (f == null)//如果首节点为空 last = newNode;//将新节点作为尾节点 else f.prev = newNode;//不为空 只修改第一个节点的前驱就可以 size++;//节点个数加1 modCount++;//修改次数加1 }
LinkedList的linkLast(E e)方法
在链尾添加一个元素
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++; }
LinkedList的linkBefore(E e, Node succ)方法
在某个节点前插入一个元素
void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev;//节点的前驱节点 final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode;//将节点的前驱改为新节点 if (pred == null)//若原来前驱为空 first = newNode;//新节点作为首节点 else pred.next = newNode;//不为空 原来前驱节点的后继节点改为新节点 size++;//节点个数加1 modCount++; }
LinkedList的add方法
//在链头添加一个元素 public void addFirst(E e) { linkFirst(e);//在链尾添加一个元素public void addLast(E e) { linkLast(e); }//一般这个方法最常用public boolean add(E e) { //此方法会返回一个boolean类型的值 linkLast(e);//是在链尾进行添加 return true; }//添加一个集合中的所有元素public boolean addAll(Collection<? extends E> c) { return addAll(size, c);//调用addAll(int index, Collection<? extends E> c)方法, //index等于size,也就是说在链尾进行添加 }//在某个节点前添加一个集合中的所有元素 public boolean addAll(int index, Collection<? extends E> c) { checkPositionIndex(index);//首先判断是否越界 Object[] a = c.toArray(); int numNew = a.length; if (numNew == 0) return false; Node<E> pred, succ; if (index == size) { succ = null; pred = last; } else { succ = node(index);//将节点作为新节点的后继 pred = succ.prev;//找出节点的前驱 } 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;//新节点作为前驱节点 } if (succ == null) { last = pred; } else { pred.next = succ;//新节点的后继节点就是该节点 succ.prev = pred; } size += numNew; modCount++; return true; }//在某个位置添加一个元素public void add(int index, E element) { checkPositionIndex(index); if (index == size)//index==size 在链尾进行添加 linkLast(element); else linkBefore(element, node(index));//在index前插入元素 }
LinkedList的get方法
//得到链头元素public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; }//得到链尾元素public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; }//得到某个位置的元素public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; }
链表中的删除
在看remove方法前先看unlink方法
LinkedList的unlink方法
//删除链头元素private E unlinkFirst(Node<E> f) { // assert f == first && f != null; final E element = f.item; final Node<E> next = f.next; f.item = null; f.next = null; // help GC 在这可以看到 删除一个节点 将该节所有属性置为null 让垃圾回收器回收 first = next; if (next == null) last = null; else next.prev = null; size--;//节点个数减1 modCount++; return element;//返回节点的值 }//删除链尾元素 private E unlinkLast(Node<E> l) { // assert l == last && l != null; final E element = l.item; final Node<E> prev = l.prev; l.item = null; l.prev = null; // help GC last = prev; if (prev == null) first = null; else prev.next = null; size--; modCount++; return element; }//在链表中删除某个指定的节点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;//该节点的前驱节点 if (prev == null) {//若前驱节点为空 则将后继节点置为头节点 first = next; } else { prev.next = next; x.prev = null; } if (next == null) {//若后继节点为空 则将前驱节点置为尾节点 last = prev; } else { next.prev = prev; x.next = null; } x.item = null;//将值置为null size--;//个数减1 modCount++; return element;//返回值 }
LinkedList的remove方法
remove方法中都是调用unlink方法
//删除并返回链头元素public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(f); }//删除并返回链尾元素public E removeLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return unlinkLast(l); }//删除某个指定的元素 public boolean remove(Object o) {//此方法不返回元素的值 只返回boolean类型的值 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; } } } return false; }//删除并返回指定位置的元素public E remove(int index) { checkElementIndex(index);//要检查指定位置是否越界 return unlink(node(index)); }
LinkedList的clear()方法
public void clear() { // Clearing all of the links between nodes is "unnecessary", but: // - helps a generational GC if the discarded nodes inhabit // more than one generation // - is sure to free memory even if there is a reachable Iterator //清除节点之间的链接是“不必要的”, //但是为了确保在有可到达的迭代器时也可以释放内存,有助于GC for (Node<E> x = first; x != null; ) { Node<E> next = x.next; x.item = null; x.next = null; x.prev = null; x = next; } first = last = null;//将所有节点置为null size = 0;//个数置为0 modCount++; }
LinkedList的indexOf(Object o)方法
该方法返回指定元素在链表中第一次出现的位置,没有该元素则返回-1
public int indexOf(Object o) { int index = 0; if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) return index; index++; } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) return index; index++; } } return -1; }
LinkedList作为队列时的操作方法
peek()方法
public E peek() { final Node<E> f = first; return (f == null) ? null : f.item;//返回链头元素的值 }
element()方法
public E element() { return getFirst();//返回链头元素的值 }
poll()方法
public E poll() { final Node<E> f = first; return (f == null) ? null : unlinkFirst(f);//调用unlinkFirst方法,删除并返回链头元素的值 }
remove()方法
public E remove() { return removeFirst();//删除并返回链头元素的值 }
offer()方法
public boolean offer(E e) { return add(e);//在链尾插入元素 }
push(E e)方法
public void push(E e) { addFirst(e);//在链头插入元素 }
pop()方法
public E pop() { return removeFirst();//删除并返回链头元素 }
LinkedList的toArray()方法
该方法将LinkedList中的元素转换成一个数组 该数组类型为Object
public Object[] toArray() { Object[] result = new Object[size]; int i = 0; for (Node<E> x = first; x != null; x = x.next) result[i++] = x.item; return result; }
LinkedList的toArray(T[] a)方法
该方法将LinkedList中的元素全部放到一个数组中并返回数组,该数组的类型为参数的指定类型
public <T> T[] toArray(T[] a) { if (a.length < size) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size); //如果数组的长度小于元素的个数,就使用反射实例化一个长度为size的新数组 int i = 0; Object[] result = a; for (Node<E> x = first; x != null; x = x.next) result[i++] = x.item; if (a.length > size)//若数组长度大于元素个数,将数组size位置置为null a[size] = null; return a; }
阅读全文
0 0
- LinkedList的深入理解
- 集合深入理解LinkedList
- 深入理解LinkedList
- LinkedList的深入理解(学习)
- 深入理解ArrayList与LinkedList的区别
- Java 集合深入理解(11):LinkedList
- 深入理解ArrayList与LinkedList的区别
- Java 集合深入理解(11):LinkedList
- JDK学习---深入理解java中的LinkedList
- Java 集合深入理解(11):LinkedList
- 深入理解ArrayList 和 LinkedList 区别
- 深入ArrayList和LinkedList
- 深入Collection之LinkedList
- 深入理解容器系列片之三--------LinkedList、Stack、Queue、PriorityQueue的总结
- Java集合(2)——深入理解ArrayList、Vector和LinkedList
- 深入理解容器系列之三--------LinkedList、Stack、Queue、PriorityQueue的总结
- LinkedList源码理解
- 深入分析LinkedList实现原理
- 文章标题
- [LeetCode]19. Remove Nth Node From End of List
- Codeforces Round #237 (Div. 2) 404B Marathon【精度】 好题!!!!
- C和C++的一点小区别
- C语言 printf格式控制符 完全解析
- 深入理解LinkedList
- leetcode之压缩字符串中的重复字符
- 快速排序(分治)
- spring容器创建对象的3种方式(bean的实例化)
- MySQL之数据库存储引擎及事务ACID特性
- ElasticSearch Java Api(一) -创建索引
- 关于mysql中基本数据类型的一些认识
- 序列得一点点知识
- 《疯狂 Java 突破程序员基本功的 16 课》读书随记