您的位置:首页 > 理论基础 > 数据结构算法

Java大课堂:常用数据结构二(List)

2015-05-20 10:21 381 查看


List框架

 

List是一个接口,继承Collection接口,但是添加了size,get等方法。由于有很多方法和Collection是重合的,因此用一个抽象类AbstractCollection来实现一些默认方法,然后AbstractList继承这个抽象类。

List家族最重要的是ArrayList和LinkedList。我主要来介绍这两个list。

 

应用场景

学东西的最终目的是为了能够理解、使用它。下面先概括的说明一下各个List的使用场景,后面再分析原因。
如果涉及到“栈”、“队列”、“链表”等操作,应该考虑用List,具体的选择哪个List,根据下面的标准来取舍。
1、对于需要快速插入,删除元素,应该使用LinkedList。
2、对于需要快速随机访问元素,应该使用ArrayList。
3、 对于“单线程环境” 或者 “多线程环境,但List仅仅只会被单个线程操作”,此时应该使用非同步的类(如ArrayList)。对于“多线程环境,且List可能同时被多个线程操作”,此时,应该使用同步的类(如Vector)。

4、因为性能问题,一般不建议用vector和stack。如需要使用栈,可以考虑deque

 

常见用法

</pre><pre name="code" class="java">public static void main(String []args){
//初始化
List<String> arrayList = Arrays.asList("abc","ab","1234");
List<String> linkedList = new LinkedList<String>(arrayList);

//遍历
for(String str : arrayList){
System.out.println(str);
}

//插入删除
arrayList.add("king");
linkedList.remove("ab");
}


 

源码分析

大家都知道,ArrayList适合随机读写。linkedList适合插入删除。那么这是为什么呢?我将从源码角度来分析这一问题。

首先来看看两者的数据结构。

在ArrayList是transient Object[] elementData.

在LinkedList是  transient Node<E> first;

可以看出两者的不同,一个是数组,另一个是指针。

现在来看看最主要的方法。add和get。

先是ArrayList。

public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

注意这个ensureCapacityInternal函数,继续向下看。

private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}

 

第一句,如果数组为默认空数组,那么最小需要的容量为max(10,inCapcity)

继续向下看。

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);
}
可以看出新的容量是原来容量的1.5倍。

这里需要分清容量和size的区别。容量是ArrayList最大能放的数据大小。Size是当前放的数据大小。

Get就比较简单,就不细说了。

    public E get(int index) {
rangeCheck(index);
return elementData(index);
}
 

现在看看LikedList的add方法。

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

linkLast是将数据放到链表最后。

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: