【數據結構】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).

相關文章
相關標籤/搜索