線性表順序存儲結(jié)構(gòu)ArrayList

線性表

  1. 線性表:零個或多個具有相同類型的數(shù)據(jù)元素的有限序列,數(shù)據(jù)元素的個數(shù)稱為線性表的長度。

  2. 線性表的存儲結(jié)構(gòu):分為順序存儲結(jié)構(gòu)和鏈式存儲結(jié)構(gòu)兩種

順序存儲結(jié)構(gòu)

用一組地址連續(xù)的存儲單元依次存儲線性表的各個數(shù)據(jù)元素

Android中以ArrayList為例,看看里面是怎么實現(xiàn)順序存儲的(基于JDK1.7源碼)

  • 構(gòu)造方法
public class ArrayList<E> extends AbstractList<E> implements Cloneable, Serializable, RandomAccess {

      ......

    /**
     * 最小容量增長值
     */
   private static final int MIN_CAPACITY_INCREMENT = 12;

    /**
     * 用一個變量記錄數(shù)組存放元素的個數(shù)
     */
    int size;
    
    /**
     * ArrayList基于數(shù)組實現(xiàn)
     */
    transient Object[] array;

      /**
     * 指定容量大小的構(gòu)造函數(shù)
     */
    public ArrayList(int capacity) {
        if (capacity < 0) {
            throw new IllegalArgumentException("capacity < 0: " + capacity);
        }
        array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
    }

    /**
     *默認構(gòu)造函數(shù),空數(shù)組
     */
    public ArrayList() {
        array = EmptyArray.OBJECT;
    }

        ......

}
  • 添加方法add(E object),將元素添加到列表的尾部
  @Override
 public boolean add(E object) {
    //將array賦值給一個局部數(shù)組
     Object[] a = array; 

    //將數(shù)組元素個數(shù)賦值給一個局部變量
     int s = size;

    //當數(shù)組元素個數(shù)等于數(shù)組長度時需要擴容  
    //(如果創(chuàng)建ArrayList為無參構(gòu)造函數(shù)(空數(shù)組,數(shù)組長度為0),  
    //那么第一次添加時:size(數(shù)組元素個數(shù))為0,數(shù)組會擴容)
     if (s == a.length) { 

    //新建一個指定容量大小的數(shù)組(當前的數(shù)組長度如果小于最小容量的一半   
    //那么新數(shù)組長度為舊數(shù)組長度加最小長度12,否則新數(shù)組長度為舊數(shù)組長度的1.5倍)
      Object[] newArray = new Object[s +
              (s < (MIN_CAPACITY_INCREMENT / 2) ?
               MIN_CAPACITY_INCREMENT : s >> 1)];

      //將舊數(shù)組的數(shù)組全部復(fù)制到新數(shù)組中
      System.arraycopy(a, 0, newArray, 0, s); 
         array = a = newArray; //將新數(shù)組復(fù)制給舊數(shù)組和array
     }
     a[s] = object; //將元素添加到數(shù)組中
     size = s + 1; //記錄數(shù)組長度的變量加1
     modCount++; // 數(shù)組元素發(fā)生變化加1
     return true; //添加成功返回true
    }
  • add(int index, E object),將元素添加到指定的位置
@Override 
public void add(int index, E object) {
     Object[] a = array;
     int s = size;
     if (index > s || index < 0) { //判斷角標是否越界
         throwIndexOutOfBoundsException(index, s);
     }

     if (s < a.length) { 
        //數(shù)組不需要擴容,將數(shù)據(jù)從index起始位置在原數(shù)組的  
        //基礎(chǔ)上整體向后復(fù)制一份到index+1的起始位置
         System.arraycopy(a, index, a, index + 1, s - index);
     } else { //數(shù)組需要擴容
         // assert s == a.length;
         Object[] newArray = new Object[newCapacity(s)];//創(chuàng)建一個指定大小的新數(shù)組
         //ps:源碼arraycopy中index為長度,注釋的index為角標
         System.arraycopy(a, 0, newArray, 0, index);//先將原數(shù)組從[0,index)(角標)復(fù)制一份到新數(shù)組[0,index)(角標)
         //ps:源碼arraycopy中s - index為長度
         System.arraycopy(a, index, newArray, index + 1, s - index);//再將原數(shù)組從[index,s-1)(角標)復(fù)制一份到新數(shù)組[index+1,s-1)(角標)
         array = a = newArray;
     }
     a[index] = object;//新數(shù)組中間留有一個index位置給新元素添加進來
     size = s + 1;
     modCount++;
    }
  • remove(int index)刪除指定位置的元素
@Override
 public E remove(int index) {
     Object[] a = array;
     int s = size;
     if (index >= s) { //判斷角標是否越界
         throwIndexOutOfBoundsException(index, s);
     }
     @SuppressWarnings("unchecked") E result = (E) a[index];
     //將數(shù)組從index+1位置復(fù)制到原數(shù)組的index位置(整體向前移動一個位置)
     System.arraycopy(a, index + 1, a, index, --s - index);
     a[s] = null;  // 將數(shù)組最后的元素置空
     size = s;
     modCount++;
     return result;
    }
  • remove(Object object)刪除列表中首次出現(xiàn)的指定元素(如果存在)
@Override
 public boolean remove(Object object) {
     Object[] a = array;
     int s = size;
     if (object != null) {
         for (int i = 0; i < s; i++) {
             if (object.equals(a[i])) {//找出元素所在的位置I
                //將數(shù)組從i+1位置復(fù)制到原數(shù)組的i位置(整體向前移動一個位置)
                 System.arraycopy(a, i + 1, a, i, --s - i);
                 a[s] = null;  // Prevent memory leak
                 size = s;
                 modCount++;
                 return true;
             }
         }
     } else {
         for (int i = 0; i < s; i++) {
             if (a[i] == null) { //移除空元素
                 System.arraycopy(a, i + 1, a, i, --s - i);
                 a[s] = null;  // Prevent memory leak
                 size = s;
                 modCount++;
                 return true;
             }
         }
     }
     return false;
 }
  • 查詢方法
@Override 
public boolean contains(Object object) {
        Object[] a = array;
        int s = size;
        if (object != null) {
            for (int i = 0; i < s; i++) {
                if (object.equals(a[i])) { //從數(shù)組起始位置開始遍歷整個數(shù)組,直到找到元素返回true
                    return true;
                }
            }
        } else {
            for (int i = 0; i < s; i++) {
                if (a[i] == null) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
     public int indexOf(Object object) {
        Object[] a = array;
        int s = size;
        if (object != null) {
            for (int i = 0; i < s; i++) {
              //從數(shù)組起始位置正向遍歷整個數(shù)組,直到找到元素返回元素角標
                if (object.equals(a[i])) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < s; i++) {
                if (a[i] == null) {
                    return i;
                }
            }
        }
        return -1; //如果沒有找到對應(yīng)的元素返回-1。
    }

    @Override public int lastIndexOf(Object object) {
        Object[] a = array;
        if (object != null) {
            for (int i = size - 1; i >= 0; i--) {
                 //從數(shù)組末尾位置反向遍歷整個數(shù)組,直到找到元素返回元素角標
                if (object.equals(a[i])) {
                    return i;
                }
            }
        } else {
            for (int i = size - 1; i >= 0; i--) {
                if (a[i] == null) {
                    return i;
                }
            }
        }
        return -1; //如果沒有找到對應(yīng)的元素返回-1。
    }
  • iterator()迭代器
 @Override public Iterator<E> iterator() {
        return new ArrayListIterator();
    }

 private class ArrayListIterator implements Iterator<E> {
     /** Number of elements remaining in this iteration */
     private int remaining = size; //留下來的個數(shù),默認為數(shù)組的長度

     /** Index of element that remove() would remove, or -1 if no such elt */
     private int removalIndex = -1;

     /** The expected modCount value */
     private int expectedModCount = modCount;

     public boolean hasNext() {
         return remaining != 0;
     }

     @SuppressWarnings("unchecked") public E next() {
         ArrayList<E> ourList = ArrayList.this;
         int rem = remaining; 
         if (ourList.modCount != expectedModCount) {
             throw new ConcurrentModificationException();
         }
         if (rem == 0) { //沒有要遍歷的元素還繼續(xù)遍歷就會拋異常
             throw new NoSuchElementException();
         }
         remaining = rem - 1;//遍歷一次留下來的個數(shù)減1
         return (E) ourList.array[removalIndex = ourList.size - rem]; //默認從角標為0開始遍歷
     }

      //迭代刪除
     public void remove() {
         Object[] a = array;
         int removalIdx = removalIndex;
         if (modCount != expectedModCount) {
             throw new ConcurrentModificationException();
         }
         if (removalIdx < 0) {
             throw new IllegalStateException();
         }
         // 迭代刪除時將數(shù)組整體向前移動一個位置,將數(shù)組末尾元素置空
         System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
         a[--size] = null;  // Prevent memory leak
         removalIndex = -1;
         expectedModCount = ++modCount;
     }
 }

總結(jié)

通過源碼分析,可以看出ArrayList是基于數(shù)組實現(xiàn)的,而且是一個動態(tài)數(shù)組,數(shù)組的容量能自動增長。
1.可以通過下標索引直接查找到指定位置的元素,因此查找效率高,但每次插入或刪除元素,就要大量地移動元素,元素越多,效率越低。
2.在聲明數(shù)組時盡量指定長度,特別是存放數(shù)據(jù)較多時,從而減少擴容提高效率。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。