本章是整理知识内容,为强化知识长期更新。
Linked List
链表即是由节点(Node)组成的线性集合,每个节点可以利用指针指向其他节点。它是一种包含了多个节点的、能够用于表示序列的数据结构。
单向链表 : 链表中的节点仅指向下一个节点,并且最后一个节点指向空。
双向链表 : 其中每个节点具有两个指针 p、n,使得 p 指向先前节点并且 n 指向下一个节点;最后一个节点的 n 指针指向 null。
循环链表 :每个节点指向下一个节点并且最后一个节点指向第一个节点的链表。
时间复杂度:
索引: O(n)
搜索: O(n)
插入: O(1)
移除: O(1)
LinkedList 是是一个有序的集合,是Collection的实现类之一。
概述
双链表 LinkedList 是 Java Collecion Framework成员之一。
双链表 是List和Deque的接口的实现。
在内部,它是使用双链表数据结构实现的。
它支持重复的元素。它没有实现RandomAccess接口。所以我们只能按顺序访问元素。它不支持随机访问元素。
相对与ArrayList它 删除 和添加 速度会快很多。但是遍历就要慢一些。
它以插入顺序存储或维护它的元素。
链表
1 2 3 4 5 6 7 8 9 10 11 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; } }
链表维护的最基本结构。在JVM中LinkedList存储并不会像数组一样按顺序来,存储的位置是随机的。
链接表结构
1 2 3 4 5 6 7 8 9 10 11 @Test public void test () { LinkedList list = new LinkedList (); list.add("a" ); list.add("b" ); list.add("c" ); list.add("d" ); System.out.println(list.toString()); System.out.println(list.getFirst()); System.out.println(list.getLast()); }
输出
linkedList的first == a next -> b next -> c next -> d next
案例-遍历LinkedList 1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void test1 () { LinkedList list = new LinkedList (); list.add("a" ); list.add("b" ); list.add("c" ); list.add("d" ); System.out.println(list.toString()); Iterator<String> itr = list.iterator(); while (itr.hasNext()){ System.out.println(itr.next()); } }
输出
都是Collection家族的使用迭代器进行遍历。
源码分析下linkedList LinkedList中的常量和变量
1 2 3 4 5 6 7 8 transient int size = 0 ; transient Node<E> first; transient Node<E> last;
1、如何创建一个LinkedList实例。 1 2 3 4 5 6 7 8 9 10 11 @Test public void test2 () { LinkedList list = new LinkedList (); list.add("a" ); list.add("b" ); list.add("c" ); list.add("d" ); String[] arr = new String []{"a" ,"b" ,"c" ,"d" }; LinkedList list1 = new LinkedList (Arrays.asList(arr)); }
创建LinkedList的实例的方式有两种。LinkedList在这点上就与ArrayList不同,不需要指定大小。
1 2 3 4 5 6 7 8 9 10 public LinkedList () {} public LinkedList (Collection<? extends E> c) { this (); addAll(c); }
2、add 方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 public boolean add (E e) { linkLast(e); return true ; } 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++; } public boolean addAll (Collection<? extends E> c) { return addAll(size, c); } 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 ; }
addAll方法会稍微麻烦点,举个栗子。
addAll 方法有两种情况,1、当前容器没有元素存在。2、当前容器已经存在元素。
1 2 3 4 5 6 7 8 @Test public void test3 () { String[] arr = new String []{"a" , "b" }; LinkedList list = new LinkedList (Arrays.asList(arr)); arr = new String []{"c" , "d" }; list.addAll(Arrays.asList(arr)); System.out.println(list); }
第二次没有每次都展示出来,不过这图画的啰嗦点。其实上debug会直接点。
1 2 3 4 5 6 7 @Test public void test5 () { String[] arr = new String []{"a" , "b" , "c" , "d" }; LinkedList list = new LinkedList (Arrays.asList(arr)); list.add(1 ,"w" ); System.out.println(list); }
输出
linkBefore 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public void add (int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); } void linkBefore (E e, Node<E> succ) { 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++; modCount++; }
3、remove
这里只介绍两个带参数的remove方法。
1 2 3 4 5 6 7 8 9 @Test public void test4 () { String[] arr = new String []{"a" ,"b" ,"c" ,"d" }; LinkedList list = new LinkedList (Arrays.asList(arr)); System.out.println(list.remove("a" )); System.out.println(list); System.out.println(list.remove(1 )); System.out.println(list); }
输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 public boolean remove (Object o) { 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)); } Node<E> node (int index) { if (index < (size >> 1 )) { Node<E> x = first; for (int i = 0 ; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1 ; i > index; i--) x = x.prev; return x; } } E unlink (Node<E> x) { 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 ; size--; modCount++; return element; }
unlink 4、poll方法 1 2 3 4 5 public E poll () { final Node<E> f = first; return (f == null ) ? null : unlinkFirst(f); }