深入研究集合-List

目錄

6.1.ArrayList

1.組成:

2.怎麼擴容

3.新增

4.插入

5、插入數組

6、刪除

6.2.LinkedList

1.組成:

2.新增

3.插入

4.刪除

6.3兩種List使用對比


參考書:《很好-Java程序性能優化.pdf》

List有三種:ArrayList、Vector和LinkedList.我們只討論Arrylist和LinkedList

以下研究都是在jdk1.7

6.1.ArrayList

討論:組成,初始化大小,怎麼擴容,怎麼插入、刪除

1.組成:

內部封裝了對數組的操作,對他進行添加、刪除、插入都是對數組的操作.

代碼:

public class ArrayList<E> {

    private static final int DEFAULT_CAPACITY = 10;//默認容量

    private transient Object[] elementData;//數組

    private int size;//數組實際存儲大小,並不是數組的大小

}

原文:https://blog.csdn.net/lan861698789/article/details/81323634

2.怎麼擴容

如果不指定容量,那麼默認容量大小就是10。

每次對數組進行添加、插入都需要判斷 內部數組是否有足夠的空間,沒有則擴容。

擴容大小爲原來大小的1.5倍。

以添加爲例,代碼:

public boolean add(E e) {

    ensureCapacityInternal(size + 1);  // Increments modCount!!

    elementData[size++] = e;

    return true;

}

private void ensureExplicitCapacity(int minCapacity) {

    modCount++;

    if (minCapacity - elementData.length > 0) {//判斷是否需要擴容

        int oldCapacity = elementData.length;//現在容量大小

        int newCapacity = oldCapacity + (oldCapacity >> 1);//擴容原來容量的1.5

        if (newCapacity - minCapacity < 0) //如果擴容後還是不能滿足,則當前容量設置爲 需要插入的大小

            newCapacity = minCapacity;

 

        elementData = Arrays.copyOf(elementData, newCapacity);//數組的擴容

    }

}

合理的數組大小,有助於減少數組擴容的次數,從而提高系統性能.

原文:https://blog.csdn.net/lan861698789/article/details/81323634

3.新增

新增是加到數組的最後一個。

代碼:

public boolean add(E e) {

    ensureCapacityInternal(size + 1);  // Increments modCount!!

    elementData[size++] = e;

    return true;

}

原理:

a.擴容一個長度

b.將數組的最後一位賦值爲要增加的元素

原文:https://blog.csdn.net/lan861698789/article/details/81323634

4.插入

任意位置添加元素.

代碼:

public void add(int index, E element) {

    ensureCapacityInternal(size + 1);  // Increments modCount!!

    System.arraycopy(elementData, index, elementData, index + 1, size - index);

    elementData[index] = element;

    size++;

}

原理:

a.擴容一個長度

b.把從插入位置的元素往後移一位

c.賦值要插入的元素

原文:https://blog.csdn.net/lan861698789/article/details/81323634

5、插入數組

和插入一個元素區別不大。

代碼:

public boolean addAll(int index, Collection<? extends E> c) {

    Object[] a = c.toArray();

    int numNew = a.length;

    ensureCapacityInternal(size + numNew);  // Increments modCount

 

    int numMoved = size - index;

    if (numMoved > 0)

        System.arraycopy(elementData, index, elementData, index + numNew, numMoved);//部分元素整體右移

 

    System.arraycopy(a, 0, elementData, index, numNew);//複製要插入的元素數組

    size += numNew;

    return numNew != 0;

}

 

原理:

原文:https://blog.csdn.net/lan861698789/article/details/81323634

6、刪除

代碼:

public E remove(int 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; // clear to let GC do its work.最後一位值賦值爲空

 

    return oldValue;

}

原文:https://blog.csdn.net/lan861698789/article/details/81323634

6.2.LinkedList

討論:組成,初始化大小,怎麼擴容,怎麼插入、刪除

1.組成:

使用了雙向鏈表的數據結構。

不需要擴容。

linkedlist只會存這個容器的長度,首、尾元素。

然後每個元素裏面包含了該元素的當前值,前一個元素,後一個元素。

代碼

public class LinkedList<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;

    }

}

原文:https://blog.csdn.net/lan861698789/article/details/81323634

原文:https://blog.csdn.net/lan861698789/article/details/81323634

2.新增

新增是往最後插的。

代碼:

void linkLast(E e) {

    final Node<E> l = last;//原來的last賦值

    final Node<E> newNode = new Node<>(l, e, null);//構建新節點,這裏把原來的last賦值給了新節點的pre

    last = newNode;//last賦值

    l.next = newNode;

    size++;

    modCount++;

}

原理:

構建新節點,把新節點的prev指向原來的最後一個節點;

把原來最後一個節點的next指向新節點。

原文:https://blog.csdn.net/lan861698789/article/details/81323634

3.插入

插入任一點

代碼:

public void add(int index, E element) {

    linkBefore(element, node(index));

}

//找出該位置的節點值

Node<E> node(int index) {

    //做了一個size判斷。是從頭循環開始找,還是從尾循環開始找

    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;

    }

}

//插入

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;

    pred.next = newNode;

    size++;

    modCount++;

}

原理:

從首or尾節點循環遍歷到該index位置,找出要插入位置的值

再進行 各種賦值。

原文:https://blog.csdn.net/lan861698789/article/details/81323634

4.刪除

刪除任意位置的值

代碼:

public E remove(int index) {

    return unlink(node(index));

}

E unlink(Node<E> x) {

    // assert x != null;

    final E element = x.item;

    final Node<E> prev = x.prev;

    final Node<E> next = x.next;

    //前面元素的next 重新賦值

    prev.next = next;

    x.prev = null;

    //後面元素的prev 重新賦值

    next.prev = prev;

    x.next = null;

    //當前元素置爲空

    x.item = null;

    size--;

    modCount++;

    return element;

}

原理:

從首or尾節點循環遍歷到該index位置,找出要插入位置的值

再進行 各種賦值。

原文:https://blog.csdn.net/lan861698789/article/details/81323634

6.3兩種List使用對比

如果是經常要進行任意位置的插入,建議使用linkedList;不使用arrayList,是因爲要頻繁擴容。

如果是經常要進行任意位置的查找,建議使用arrayList;不使用linkedlist,是因爲要循環查找。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章