1. 程式人生 > >自已實現一個數組

自已實現一個數組

前言:

         最近開始學習資料結構,剛學到陣列,寫下此篇部落格記錄下學習內容。如文中有不對的地方還請大佬指出。

正文:

        1.陣列(Array):陣列是一種線性表資料結構,它是一組連續的空間和相同的資料型別組成。

        2.資料的時間複雜度分析:

           1)插入:最好的情況為O(1),最壞的情況為O(n),均攤為O(n)。

           2)  刪除:最好的情況為O(1),最壞的情況為O(n),均攤為O(n)。

           3)查詢:最好的情況為O(1),最壞的情況為O(n),均攤為O(n)。

       原因:

       插入:如果在索引3處插入一個新的值20,因為陣列是一組連續的空間,為了保持資料的連續性,資料將會進行資料搬移動作,將索引3及後面的值向後移動,造成大量的時間消耗。最好的情況就是在陣列的最後一個位置進行插入操作,這樣就避免了大量的資料搬移。如果不需要資料的連續性,可以考慮將3處的值移動到陣列末尾處,然後在將值插入到3處,這樣就避免的資料的搬移。

       刪除:跟插入相似,不過是將資料往前搬移。可以考慮將要刪除的值做個標記,等陣列記憶體不夠用時統一做刪除操作。

                                        圖片是用excel製作的,有點醜。

                                       

                                       

      查詢:陣列查詢需要遍歷,遍歷需要O(n)的時間。當需要查詢某個值時如果這個值剛好在下標0處那麼時間複雜度就為O(1),這種情況一般很少見。如果是排好序的陣列通過二分法查詢時間複雜度就是O(logn)。

3.陣列的優缺點

       缺點:因為資料是一組連續的空間,所以當沒有連續的空間時,就沒有足夠的記憶體分配。例:當我們需要建立一個100M的陣列時,此時虛擬機器記憶體剛好只剩100M,但不是連續的,就會造成記憶體不夠分配。

       優點:陣列支援隨機訪問(也就是直接通過下標訪問),時間複雜度為O(1)。

 4.陣列的定址公式:array[i]_address = first_address + i * data_type_size;  first_address是陣列第一個元素所在的記憶體地址,i是下標,data_type_size是資料型別大小。

       例:比如說我們要找到下標3的記憶體地址,第一個元素的記憶體地址是1024,資料型別是int型別,int型別佔4個位元組。那麼array[3]_address = 1024 + 3 * 4;就是下標3的記憶體地址了。

5.下面開始用程式碼實現一個自已的陣列,我使用的是Java語言編寫的。

/**
 * @author zhouyun
 * @email [email protected]
 * @Description: 自定義陣列
 * @Date 2018/12/22 17:28
 * @Version 1.0
 **/
public class CustomArray<E> {
    /**
     * 陣列
     */
    private E[] data;
    /**
     * 陣列元素的個數
     */
    private int size;

    /**
     * 指定大小的構造器
     */
    public CustomArray(int capacity){
        //大於0才建立陣列
        if(capacity > 0) {
            data = (E[]) new Object[capacity];
            size = 0;
        }else {
            throw new IllegalArgumentException("Illegal Capacity:  "+ capacity);
        }
    }

    /**
     * 預設陣列大小為10
     */
    public CustomArray(){
        this(10);
    }

    /**
     *  獲取元素的個數
     */
    public int getSize(){
        return size;
    }

    /**
     *  獲取陣列的容量
     */
    public int getCapacity(){
        return data.length;
    }

    /**
     *  陣列元素是否為空
     */
    public boolean isEmpty(){
        return size == 0;
    }

    /**
     * 向陣列末尾新增元素
     */
    public void addLast(E e){
        add(size,e);
    }

    /**
     *  向陣列第一位新增元素
     */
    public void addFirst(E e){
        add(0,e);
    }

    /**
     *  在指定索引處新增元素
     */
    public void add(int index,E e){
        //陣列是否存滿
        if(size == data.length){
            throw new IllegalArgumentException("Array space is exhausted");
        }
        //索引非法
        if(index <0 || index > data.length){
            throw new ArrayIndexOutOfBoundsException("Array index out of range: " + index);
        }
        //搬移資料
        for (int i=size -1;i >= index;i--){
            data[i + 1] = data[i];
        }
        data[index] = e;
        size ++;
    }

    /**
     *  獲取指定索引處的值
     */
    public E get(int index){
        //索引非法
        if(index < 0 || index > data.length){
            throw new ArrayIndexOutOfBoundsException("Array index out of range: " + index);
        }
        return data[index];
    }

    /**
     *  修改指定索引處的值
     */
    public void set(int index,E e){
        //索引非法
        if(index <0 || index > data.length){
            throw new ArrayIndexOutOfBoundsException("Array index out of range: " + index);
        }
        data[index] = e;
    }

    /**
     *  刪除指定索引處的值
     */
    public void remove(int index){
        //索引非法
        if(index <0 || index > data.length){
            throw new ArrayIndexOutOfBoundsException("Array index out of range: " + index);
        }
        //資料搬移
        for (int i = index + 1 ; i < size  ; i++) {
            data[i-1] = data[i ];
        }
        //將最後一個元素的值設定為null
        data[size -1 ] = null;
        size --;
    }

    /**
     *  刪除某一個元素
     */
    public boolean removeElement(E e){
        //呼叫查詢方法,尋找元素的索引
        //只刪除找到的第一個
        int i = find(e);
        //找到則執行刪除操作
        if(i != -1){
            remove(i);
            return true;
        }
        return false;
    }

    /**
     *  查詢陣列中是否包含某個值
     *  包含返回true,否則返回false
     */
    public boolean contains(E e){
        for (int i = 0; i < data.length; i++) {
            if(data[i].equals(e)){
                return true;
            }
        }
        return false;
    }

    /**
     *  查詢指定內容的索引
     *  如果未找到,返回-1
     */
    public int find(E e){
        for (int i = 0; i < data.length; i++) {
            if(data[i].equals(e)){
                return i;
            }
        }
        return -1;
    }


    /**
     * 重寫toString 方便列印
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("Array: size=%d ,capacity=%d \n",size,data.length));
        sb.append("[");
        for (int i=0;i<size;i++){
            sb.append(data[i]);
            if(i != size -1 ){
                sb.append(" , ");
            }
        }
        sb.append("]");
        return sb.toString();
    }

}


/**
 * @author zhouyun
 * @email [email protected]
 * @Description  自定義陣列測試類
 * @Date 2018/12/22 22:28
 * @Version 1.0
 **/
public class CustomArrayTest {

    public static void main(String[] args) {
        CustomArray<Integer> customArray = new CustomArray();
        for (int i = 0; i < customArray.getCapacity(); i++) {
            //向陣列末尾插入元素
            customArray.addLast(i );
        }
        //測試刪除
        customArray.remove(2);
        //測試指定索引新增
        customArray.add(9,10);
        //測試查詢
        System.out.println("查詢結果: " + customArray.find(5 ));
        //測試獲取指定索引的值
        System.out.println("指定索引位置的值: " + customArray.get(5 ));
        //測試包含
        System.out.println("陣列中是否包含這個元素: " + customArray.contains(6));
        //列印輸出陣列元素
        System.out.println(customArray);
    }
}