JAVA中ArrayList和LinkedList的区别

JAVA中ArrayList和LinkedList的区别

ArrayList和LinkedList的大致区别如下:

1.ArrayList是基于动态数组的数据结构实现,LinkedList是基于双向链表实现。
2.对于随机访问的get和set方法,ArrayList要优于LinkedList,因为ArrayList基于数组,获取任意元素的位置时间复杂度为O(1),LinkedList基于链表,时间复杂度则为O(n)。
3.对于新增和删除操作add和remove,LinkedList比较占优势,因为如果ArrayList不是在尾部进行新增和删除时数组会进行前移或后移。

具体说明
构造函数
ArrayList

在不指定容量时,构造一个初始容量为 10 的空数组,不过在第一次插入时才会分配初始容量为 10 的空数组。

transient Object[] elementData;

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
LinkedList

因为LinkedList是基于双向链表,链表不需要分配连续的内存空间,所以无参构造中无任何操作。

/**
* Constructs an empty list
* */
public LinkedList() {}
插入操作
ArrayList

可以看到通过下面的源码看到,ArrayList在尾部插入时,先去检查内部容量,若为DEFAULTCAPACITY_EMPTY_ELEMENTDATA(不指定容量生产ArrayList对象时)则分配初始容量为 10 的空数组,若容量不足则进行扩容,扩容为原数组大小右移一位加上原数组大小,约为1.5倍,为什么是1.5倍呢,需要考虑如下情况:
1.扩容容量不能太小,防止频繁扩容,频繁申请内存空间 + 数组频繁复制
2.扩容容量不能太大,需要充分利用空间,避免浪费过多空间

为了能充分使用之前分配的内存空间,最好把增长因子设为 1<k<2,并且充分利用移位操作(右移一位),减少浮点数或者运算时间和运算次数。
不在尾部插入时,则是使用了System.arraycopy()方法进行了数组的后移。

private static int calculateCapacity(Object[] elementData, int minCapacity) {
	if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
  		 return Math.max(DEFAULT_CAPACITY, minCapacity);
	}
	return minCapacity;
}

private void ensureCapacityInternal(int minCapacity) {
	ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private void ensureExplicitCapacity(int minCapacity) {
	modCount++;
	// overflow-conscious code
	if (minCapacity - elementData.length > 0)
   		grow(minCapacity);
}

/**
* 扩容
*/
private void grow(int minCapacity) {
	// overflow-conscious code
	int oldCapacity = elementData.length;
	int newCapacity = oldCapacity + (oldCapacity >> 1);
	if (newCapacity - minCapacity < 0)
	    newCapacity = minCapacity;
	if (newCapacity - MAX_ARRAY_SIZE > 0)
	    newCapacity = hugeCapacity(minCapacity);
	// minCapacity is usually close to size, so this is a win:
	elementData = Arrays.copyOf(elementData, newCapacity);
}
 
public boolean add(E e) {
	ensureCapacityInternal(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
}

public void add(int index, E element) {
	rangeCheckForAdd(index);
	ensureCapacityInternal(size + 1);  // Increments modCount!!
	System.arraycopy(elementData, index, elementData, index + 1,
					size - index);
	elementData[index] = element;
	size++;
}
LinkedList

LinkedList的插入则是修改Node节点中的前驱节点(prev)与后驱节点(next)进行插入,若是尾部插入则next为null。

public boolean add(E e) {
	linkLast(e);
	return true;
}

public void add(int index, E element) {
	checkPositionIndex(index);
	if (index == size)
		linkLast(element);
	else
		linkBefore(element, node(index));
}

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++;
}

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++;
	modCount++;
}
删除操作

ArrayList删除时,也是使用了System.arraycopy()方法进行了数组的前移,LinkedList则是通过修改prev和next进行remove操作,故删除时LinkedList效率比ArrayList高。

获取数据

ArrayList直接通过数组下标获取,LinkedList则是通过遍历的方式进行获取,不过并不是重头节点开始进行便利,为了提高效率,元素下标小于长度的一半则从头部开始遍历,否则从尾部开始遍历,这样便提高了遍历的效率。

public E get(int index) {
	checkElementIndex(index);
	return node(index).item;
}

Node<E> node(int index) {
// assert isElementIndex(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;
	}
}
ArrayList和LinkedList的缺点如下:
  1. 对ArrayList和LinkedList而言,在末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部对象。
  2. 在ArrayList集合中添加或者删除一个元素时,当前的数组移动元素后面的所有元素都会被移动。而在LinkedList中添加或者删除一个元素的开销是固定的。
  3. LinkedList集合不支持高效的随机随机访问, ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间。在ArrayList数组预留空间不足时,要进行数组的扩容,而LinkedList则不需要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值