18.2.3 ArrayList vs LinkedList性能对比
1. 数据结构基础
1.1 ArrayList底层实现
ArrayList基于动态数组实现,内部使用Object[]数组存储元素。
public class ArrayList<E> extends AbstractList<E> implements List<E> { // 默认初始容量 private static final int DEFAULT_CAPACITY = 10; // 存储元素的数组 transient Object[] elementData; // 实际元素数量 private int size; // 构造方法 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); } } }
1.2 LinkedList底层实现
LinkedList基于双向链表实现,每个节点包含数据和前后指针。
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E> { // 链表大小 transient int size = 0; // 头节点 transient Node<E> first; // 尾节点 transient Node<E> last; // 节点结构 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; } } // 构造方法 public LinkedList() { } public LinkedList(Collection<? extends E> c) { this(); addAll(c); } }
2. 核心操作性能分析
2.1 随机访问性能对比
ArrayList随机访问
public class ArrayListRandomAccess { // ArrayList的get方法 - O(1) public E get(int index) { rangeCheck(index); // 边界检查 return elementData(index); // 直接数组访问 } E elementData(int index) { return (E) elementData[index]; } // 性能测试 public void testRandomAccess() { ArrayList<Integer> arrayList = new ArrayList<>(); // 添加10万个元素 for (int i = 0; i < 100000; i++) { arrayList.add(i); } long startTime = System.nanoTime(); // 随机访问1万次 Random random = new Random(); for (int i = 0; i < 10000; i++) { int index = random.nextInt(arrayList.size()); Integer value = arrayList.get(index); } long endTime = System.nanoTime(); System.out.println("ArrayList随机访问耗时: " + (endTime - startTime) / 1000000 + "ms"); } }
LinkedList随机访问
public class LinkedListRandomAccess { // LinkedList的get方法 - O(n) public E get(int index) { checkElementIndex(index); return node(index).item; } // 根据索引查找节点 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; } } // 性能测试 public void testRandomAccess() { LinkedList<Integer> linkedList = new LinkedList<>(); // 添加10万个元素 for (int i = 0; i < 100000; i++) { linkedList.add(i); } long startTime = System.nanoTime(); // 随机访问1万次 Random random = new Random(); for (int i = 0; i < 10000; i++) { int index = random.nextInt(linkedList.size()); Integer value = linkedList.get(index); } long endTime = System.nanoTime(); System.out.println("LinkedList随机访问耗时: " + (endTime - startTime) / 1000000 + "ms"); } }
2.2 插入操作性能对比
ArrayList插入操作
public class ArrayListInsert { // 尾部插入 - O(1) 均摊时间复杂度 public boolean add(E e) { ensureCapacityInternal(size + 1); // 确保容量 elementData[size++] = e; return true; } // 指定位置插入 - O(n) public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // 移动元素 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } // 扩容机制 private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容1.5倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); } // 性能测试 public void testInsertPerformance() { ArrayList<Integer> list = new ArrayList<>(); // 测试尾部插入 long startTime = System.nanoTime(); for (int i = 0; i < 100000; i++) { list.add(i); } long endTime = System.nanoTime(); System.out.println("ArrayList尾部插入耗时: " + (endTime - startTime) / 1000000 + "ms"); // 测试头部插入 list.clear(); startTime = System.nanoTime(); for (int i = 0; i < 10000; i++) { list.add(0, i); // 头部插入 } endTime = System.nanoTime(); System.out.println("ArrayList头部插入耗时: " + (endTime - startTime) / 1000000 + "ms"); } }
LinkedList插入操作
public class LinkedListInsert { // 尾部插入 - O(1) 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++; } // 指定位置插入 - O(n) 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++; } // 头部插入 - O(1) public void addFirst(E e) { linkFirst(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++; modCount++; } // 性能测试 public void testInsertPerformance() { LinkedList<Integer> list = new LinkedList<>(); // 测试尾部插入 long startTime = System.nanoTime(); for (int i = 0; i < 100000; i++) { list.add(i); } long endTime = System.nanoTime(); System.out.println("LinkedList尾部插入耗时: " + (endTime - startTime) / 1000000 + "ms"); // 测试头部插入 list.clear(); startTime = System.nanoTime(); for (int i = 0; i < 100000; i++) { list.addFirst(i); // 头部插入 } endTime = System.nanoTime(); System.out.println("LinkedList头部插入耗时: " + (endTime - startTime) / 1000000 + "ms"); } }
2.3 删除操作性能对比
ArrayList删除操作
public class ArrayListRemove { // 根据索引删除 - O(n) 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; // 清除引用 return oldValue; } // 根据对象删除 - O(n) public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; } private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; } // 性能测试 public void testRemovePerformance() { ArrayList<Integer> list = new ArrayList<>(); // 准备数据 for (int i = 0; i < 100000; i++) { list.add(i); } // 测试头部删除 long startTime = System.nanoTime(); for (int i = 0; i < 10000; i++) { if (!list.isEmpty()) { list.remove(0); // 头部删除 } } long endTime = System.nanoTime(); System.out.println("ArrayList头部删除耗时: " + (endTime - startTime) / 1000000 + "ms"); } }
LinkedList删除操作
public class LinkedListRemove { // 根据索引删除 - O(n) public E remove(int index) { checkElementIndex(index); return unlink(node(index)); } // 删除头部元素 - O(1) public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(f); } private E unlinkFirst(Node<E> f) { final E element = f.item; final Node<E> next = f.next; f.item = null; f.next = null; first = next; if (next == null) last = null; else next.prev = null; size--; modCount++; return element; } // 删除节点 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; } // 性能测试 public void testRemovePerformance() { LinkedList<Integer> list = new LinkedList<>(); // 准备数据 for (int i = 0; i < 100000; i++) { list.add(i); } // 测试头部删除 long startTime = System.nanoTime(); for (int i = 0; i < 10000; i++) { if (!list.isEmpty()) { list.removeFirst(); // 头部删除 } } long endTime = System.nanoTime();
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经