【数据结构】ArrayList原理及实现学习总结

关于Java集合的小抄中是这样描述的:html

以数组实现。节约空间,但数组有容量限制。超出限制时会增长50%容量,用System.arraycopy()复制到新的数组,所以最好能给出数组大小的预估值。默认第一次插入元素时建立大小为10的数组。java

按数组下标访问元素—get(i)/set(i,e) 的性能很高,这是数组的基本优点。git

直接在数组末尾加入元素—add(e)的性能也高,但若是按下标插入、删除元素—add(i,e), remove(i), remove(e),则要用System.arraycopy()来移动部分受影响的元素,性能就变差了,这是基本劣势。github

 

而后再来学习一下官方文档:数组

Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)数据结构

ArrayList是一个相对来讲比较简单的数据结构,最重要的一点就是它的自动扩容,能够认为就是咱们常说的“动态数组”。
来看一段简单的代码:ide

1
2
3
4
5
ArrayList<String> list = new ArrayList<String>();
list.add( "语文: 99" );
list.add( "数学: 98" );
list.add( "英语: 100" );
list.remove( 0 );

在执行这四条语句时,是这么变化的:

其中,add操做能够理解为直接将数组的内容置位,remove操做能够理解为删除index为0的节点,并将后面元素移到0处。函数

2. add函数

当咱们在ArrayList中增长元素的时候,会使用add函数。他会将元素放到末尾。具体实现以下:性能

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

咱们能够看到他的实现其实最核心的内容就是ensureCapacityInternal。这个函数其实就是自动扩容机制的核心。咱们依次来看一下他的具体实现学习

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
private void ensureCapacityInternal( int minCapacity) {
     if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
         minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
     }
 
     ensureExplicitCapacity(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;
     // 扩展为原来的1.5倍
     int newCapacity = oldCapacity + (oldCapacity >> 1 );
     // 若是扩为1.5倍还不知足需求,直接扩为需求值
     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);
}

也就是说,当增长数据的时候,若是ArrayList的大小已经不知足需求时,那么就将数组变为原长度的1.5倍,以后的操做就是把老的数组拷到新的数组里面。例如,默认的数组大小是10,也就是说当咱们add10个元素以后,再进行一次add时,就会发生自动扩容,数组长度由10变为了15具体状况以下所示:

3 set和get函数

Array的put和get函数就比较简单了,先作index检查,而后执行赋值或访问操做:

1
2
3
4
5
6
7
8
9
10
11
12
13
public E set( int index, E element) {
     rangeCheck(index);
 
     E oldValue = elementData(index);
     elementData[index] = element;
     return oldValue;
}
 
public E get( int index) {
     rangeCheck(index);
 
     return elementData(index);
}

4 remove函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);
     // 把最后的置null
     elementData[--size] = null ; // clear to let GC do its work
 
     return oldValue;
}

注释很清楚:

Removes the element at the specified position in this list. Shifts any subsequent elements to the left (subtracts one from their indices).

相关文章
相关标签/搜索