Java ADT
ArrayList
List接口的可增长数组的实现
类似于数组的特点,ArrayList的插入和删除代价比较高,但在get / set操作只会消耗常数时间。
LinkedList
List接口的双链表实现
实际上对于LinkedList而言在表的中段删除和插入仍然是一个开销很大的过程,在测试中,一个长度为10000的LinkedList重复 remove(li.size()/2)或者add(li.size()/2,arg)操作10000次,LinkedList中段的实际效率表现低于ArrayList,且差距比较明显。但LinkedList在表头插入和删除的效率远远大于ArrayList。
另外有一点需要说明,LinkedList迭代器Iterator的remove()方法其效率是非常高的,因为Iterator调用remove的时候已经是基本知道了目标元素的位置。
get / set的开销相较于ArrayList是比较大的,这也是LinkedList在中段插入或删除效率低下的原因。
实例1:对比LinkedList和ArrayList在对0位置的插入效率
package ryo; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class ListTest { public static void main(String[] args) { set(new ArrayList<Integer>() ,10000); set(new LinkedList<Integer>() ,10000); } public static void set(List<Integer> li ,int times) { long before = System.currentTimeMillis(); for(int i=0 ;i<times ;i++) { li.add(0 ,i); } long after = System.currentTimeMillis(); System.out.println(li.getClass().getName()+" :"+(after-before)+"ms"); } }
实例2:对比LinkedList和ArrayList在get(length/2)的效率
package ryo; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class ListTest { public static void main(String[] args) { set(new ArrayList<Integer>() ,10000); set(new LinkedList<Integer>() ,10000); } public static void set(List<Integer> li ,int times) { for(int i=0 ;i<times ;i++) { li.add(0,1); } long before = System.currentTimeMillis(); for(int i=0 ;i<times ;i++) { li.get(times/2); } long after = System.currentTimeMillis(); System.out.println(li.getClass().getName()+" :"+(after-before)+"ms"); } }
但在get表头或者表尾的时候,LinkedList表现几乎与ArrayList一致,受益于LinkedList的双链表结构,靠近表尾的get操作将从表尾向前进行
实例3:对比LinkenList和ArrayList在remove(size/2)的效率
代码沿用实例2的代码,只将get改为了remove(li.size()/2);
ArrayList和LinkedList的源码解析
这里主要对LinkedList进行分析,ArrayList的实现其实并不算太难,很多操作都使用了System.arraycopy,受制于数组的特性,只能进行拷贝再复制回原数组的操作,就拿remove来说:
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }
这里还是主要想说明一下LinkedList实现,其中包含了双链表结构的实现,双链表被抽象为一个名为Node的内部类:
//LinkedList的内部类 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的remove public E remove(int index) { checkElementIndex(index); return unlink(node(index)); } //判断index的合法性 private void checkElementIndex(int index) { if (!isElementIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } //此方法将返回index位置的node Node<E> node(int index) { //这里的>>意为右移 等同于size/2 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; } } //移除节点x的连接关系 E unlink(Node<E> x) { final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; //如果x是首位 则linkedList的firstnode变为x的nextnode if (prev == null) { first = next; } else { prev.next = next;//x的前节点next指向x的后节点 x.prev = null; } if (next == null) { last = prev; } else { next.prev = prev;//x的后节点prev指向x的前节点 x.next = null; } x.item = null;//这里赋null主要是为了GC该实例内存 size--; modCount++; return element; }
这里是我自定义的一个简单的单链表结构,不是很完善,但基本功能是齐全的
package com.ryo.structure.linkedlist; import com.ryo.structure.DataStructure; /** * 自定义的一个单链表 * 未对insert方法进行重写 * 未设置一个检查index合法性的方法 * @author shiin * @param <T> 存储类型 */ public class SinglyLinkedList<T> implements DataStructure<T>{ private Node<T> first; private Node<T> last; private int size; public SinglyLinkedList(){ } public SinglyLinkedList(T[] arr) { this(); addArray(arr); } private void addArray(T[] arr) { if(arr == null || arr.length == 0) { return; } else { size = arr.length; @SuppressWarnings("unchecked") Node<T>[] temp = new Node[arr.length]; for(int i=0 ;i<size ;i++) { temp[i] = new Node<T>(arr[i] ,null); } for(int i=0 ;i<size-1 ;i++) { temp[i].next = temp[i+1]; } first = temp[0]; last = temp[size-1]; } } @Override public void insert(T newEn) { return; } @Override public void delete(int index) { if(index < 0) { return; } else if(index == 0) { if(first.next != null) { first = first.next; } } else{ beforeIndexNode(index).next = beforeIndexNode(index+2); } size--; } @Override public int size() { return this.size; } @Override public void add(T newEn) { Node<T> newlast = new Node<T>(newEn ,null); last.next = newlast; this.last = newlast; size++; } @Override public T get(int index) { if(index == 0) { return first.item; } else return beforeIndexNode(index).next.item; } /** * 返回目标节点之前的一个节点 * 因为删除方法需要改变前一个节点的next * @param index 目标索引 * @return index-1位置的node */ private Node<T> beforeIndexNode(int index){ if(index == 1) { return first; } else { Node<T> temp = first; for(int i=0 ;i<index-1 ;i++) { temp = temp.next; } return temp; } } /** * 单链表的节点 * @author shiin * @param <T> */ private static class Node<T>{ T item; Node<T> next; Node(T item ,Node<T> next){ this.item = item; this.next = next; } } }