資料結構-陣列

致于数据科学家的小陈發表於2024-03-26

陣列

認識陣列

陣列, 是我們學習資料結構最基礎的一種了, 無論是什麼語言都有陣列。 我們又如何去理解陣列呢? 陣列有哪些特點呢?

理解陣列
  • 陣列是由相同型別的元素的集合所組成的資料結構
  • 連續的記憶體來儲存
  • 利用元素的索引(index)獲取對應值, 索引值從0開始
  • 請求記憶體空間後大小固定, 不能在改變
  • 陣列可以存在一維二維甚至更多
  • 陣列的刪除和新增都需要移動元素

那麼, 程式中又是怎麼定義一個陣列呢?

程式中也分幾步

  • 陣列型別 + 中括號
  • 陣列名稱
  • 如果能直接定義的話, 就直接寫{"需要的內容"}, 如果是初始化需要new [長度]
String[] names = {"xiaomoyu", "666", "999"}; // 直接寫入, 我們知道就是這些值
int[] scores = new int[3]; // 還不知道後面要寫什麼, 先定義好
scores[0] = 1;
scores[1] = 2;
scores[2] = 3;
複製程式碼

用一張圖片來表示一下陣列把。

avatar

自定義陣列

經過上面的學習, 我們已經瞭解到陣列的基本使用, 但是我覺得就是這麼使用不是我想要的, 我想要對陣列做一些封裝。

那麼我從下面幾個方面介紹一下:

  • 陣列的容量
  • 陣列的實際儲存元素量
  • 預設陣列容量
  • 陣列是否為空
  • 獲取陣列容量
  • 獲取陣列實際儲存元素數量
  • 增刪改查
  • 動態擴充套件

我們來看看怎麼設計這樣的一個陣列?

avatar

陣列有儲存實際元素的大小, 有一個陣列的總大小, 我們可以對陣列進行增刪改查操作。 當存入一個實際元素的的時候size就加1, 當刪除一個元素的時候size就減1.

我們來建立一個Array類來實現上述功能



public class Array {

    private static final int DEFAULT_CAPACITY = 10;

    private int[] data; // 陣列容量
    private int size; // 存放了多少元素


    /***
     * 提供初始化大小的陣列
     * @param capacity
     */
    public Array(int capacity) {
        this.data = new int[capacity];
        this.size = 0;
    }

    /**
     * 提供預設初始化大小陣列
     */
    public Array() {
        this(DEFAULT_CAPACITY);
    }

    /**
     * @return 實際元素個數
     */
    public int getSize() {
        return size;
    }

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

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

    /**
     * 向陣列頭部新增元素
     * @param e
     */
    public void addFirst(int e) {
        add(0, e);
    }

    /**
     * 向陣列末尾新增元素
     * @param e 實際值
     */
    public void addLast(int e) {
//        if (size >= data.length) {
//            throw new IllegalArgumentException("陣列已滿.");
//        }
//
//        // 把元素新增到陣列末尾
//        data[size] = e;
//        // 實際元素加1, 否則陣列一直覆蓋當前下標的值
//        size++;
        add(size, e);
    }

    /***
     * 向陣列指定位置新增元素
     * @param index 指定下標的位置
     * @param e 元素值
     */
    public void add(int index, int e) {

        if (size >= data.length) {
            throw new IllegalArgumentException("陣列已滿.");
        }

        if (index < 0 || index > size) {
            throw new IllegalArgumentException("請輸入正確的下標位置");
        }

        // 將陣列的元素向後面移動
        for (int i = size; i > index; i--) {
            data[i] = data[i - 1];
        }

        // 元素移動完畢後, 直接指定對應的下標值賦值
        data[index] = e;
        size ++;
    }


    /**
     * 刪除陣列頭部
     * @return
     */
    public int removeFirst() {
        return remove(0);
    }

    /***
     * 刪除陣列尾部
     * @return
     */
    public int removeLast() {
        return remove(size - 1);
    }

    /**
     * 刪除指定元素
     * @param e
     */
    public void removeElement(int e) {
        int removeElementIndex = find(e);
        remove(removeElementIndex);
    }

    /***
     * 刪除指定位置元素
     * @param index
     * @return
     */
    public int remove(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("請輸入正確的下標值");
        }

        int removeElement = get(index);
        // 把後面的元素值寫入到前一個元素位置
        for (int i = index; i < size - 1; i++) {
            data[i] = data[i + 1];
        }

        size --;
        return removeElement;
    }

    /***
     * 獲取index索引位置的元素
     * @param index
     * @return
     */
    public int get(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("輸入正確的下標");
        }

        return data[index];
    }


    /***
     * 修改index元素的值為e
     * @param index
     * @param e
     */
    public void set(int index, int e) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("輸入正確的下標");
        }

        data[index] = e;
    }

    /**
     * 判斷陣列是否包含元素
     * @param e
     * @return
     */
    public boolean contains(int e) {
        for (int i = 0; i < size; i++) {
            if (data[i] == e) {
                return true;
            }
        }

        return false;
    }

    /**
     * 查詢元素, 如果找到元素返回對應的下標, 否則返回-1
     * @param e
     * @return
     */
    public int find(int e) {
        for (int i = 0 ; i < size; i ++) {
            if (data[i] == e) {
                return i;
            }
        }

        return -1;
    }


    @Override
    public String toString() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("[");
        for (int i = 0; i < size; i ++) {
            if (i < size - 1) {
                buffer.append(data[i]).append(",");
            } else {
                buffer.append(data[i]);
            }
        }

        buffer.append("]");

        return String.format("陣列的元素為: %s 陣列容量為: %s\n%s", size, getCapacity(), buffer.toString());
    }
}

複製程式碼

向陣列末尾新增元素流程如下圖:

avatar

向陣列任意位置新增元素流程如下圖:

avatar

向陣列任意位置刪除元素流程如下圖:

avatar

陣列泛型

使用泛型,可以讓我們的陣列放入“任意”資料型別。 但是不可以放基本資料型別, 只能放類物件, java中基本型別有8種

boolean, byte, char, short, int, long, float, double

那我們如果要放基本型別怎麼實現呢? 彆著急JDK給我們做了包裝類, 分別對應上面8種的基本型別

Boolean, Byte, Char, Short, Integer, Long, Float, Double

這樣, 我們就可以使用了。

我們更新使用泛型後, Array類為



public class Array<E> {

    private static final int DEFAULT_CAPACITY = 10;

    private E[] data; // 陣列容量
    private int size; // 存放了多少元素


    /***
     * 提供初始化大小的陣列
     * @param capacity
     */
    public Array(int capacity) {
        // 需要注意的就是, 泛型陣列需要先用Object建立然後強轉為泛型
        this.data = (E[]) new Object[capacity];
        this.size = 0;
    }

    /**
     * 提供預設初始化大小陣列
     */
    public Array() {
        this(DEFAULT_CAPACITY);
    }

    /**
     * @return 實際元素個數
     */
    public int getSize() {
        return size;
    }

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

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

    /**
     * 向陣列頭部新增元素
     * @param e
     */
    public void addFirst(E e) {
        add(0, e);
    }

    /**
     * 向陣列末尾新增元素
     * @param e 實際值
     */
    public void addLast(E e) {
//        if (size >= data.length) {
//            throw new IllegalArgumentException("陣列已滿.");
//        }
//
//        // 把元素新增到陣列末尾
//        data[size] = e;
//        // 實際元素加1, 否則陣列一直覆蓋當前下標的值
//        size++;
        add(size, e);
    }

    /***
     * 向陣列指定位置新增元素
     * @param index 指定下標的位置
     * @param e 元素值
     */
    public void add(int index, E e) {

        if (size >= data.length) {
            throw new IllegalArgumentException("陣列已滿.");
        }

        if (index < 0 || index > size) {
            throw new IllegalArgumentException("請輸入正確的下標位置");
        }

        // 將陣列的元素向後面移動
        for (int i = size; i > index; i--) {
            data[i] = data[i - 1];
        }

        // 元素移動完畢後, 直接指定對應的下標值賦值
        data[index] = e;
        size ++;
    }


    /**
     * 刪除陣列頭部
     * @return
     */
    public E removeFirst() {
        return remove(0);
    }

    /***
     * 刪除陣列尾部
     * @return
     */
    public E removeLast() {
        return remove(size - 1);
    }

    /**
     * 刪除指定元素
     * @param e
     */
    public void removeElement(E e) {
        int removeElementIndex = find(e);
        remove(removeElementIndex);
    }

    /***
     * 刪除指定位置元素
     * @param index
     * @return
     */
    public E remove(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("請輸入正確的下標值");
        }

        E removeElement = get(index);
        // 把後面的元素值寫入到前一個元素位置
        for (int i = index; i < size - 1; i++) {
            data[i] = data[i + 1];
        }

        size --;
        return removeElement;
    }

    /***
     * 獲取index索引位置的元素
     * @param index
     * @return
     */
    public E get(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("輸入正確的下標");
        }

        return data[index];
    }

    // 獲取第一個元素
    public E getFirst() {
        return get(0);
    }

    // 獲取最後一個元素
    public E getLast() {
        return get(size - 1);
    }


    /***
     * 修改index元素的值為e
     * @param index
     * @param e
     */
    public void set(int index, E e) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("輸入正確的下標");
        }

        data[index] = e;
    }

    /**
     * 判斷陣列是否包含元素
     * @param e
     * @return
     */
    public boolean contains(E e) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(e)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 查詢元素, 如果找到元素返回對應的下標, 否則返回-1
     * @param e
     * @return
     */
    public int find(E e) {
        for (int i = 0 ; i < size; i ++) {
            if (data[i].equals(e)) {
                return i;
            }
        }

        return -1;
    }


    @Override
    public String toString() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("[");
        for (int i = 0; i < size; i ++) {
            if (i < size - 1) {
                buffer.append(data[i]).append(",");
            } else {
                buffer.append(data[i]);
            }
        }

        buffer.append("]");

        return String.format("陣列的元素為: %s 陣列容量為: %s\n%s", size, getCapacity(), buffer.toString());
    }
}

複製程式碼

動態陣列

先通過一張圖片來了解一下, 陣列是如何動態擴容的。

avatar


public void add(int index, E e) {
  if (size >= data.length) {
//            throw new IllegalArgumentException("陣列已滿.");
            // 動態擴容陣列
            resize(data.length * 2);
        }
}

public E remove(int index) {

  // 如果當前元素個數小到當前陣列的一半, 整個陣列只有一半被利用, 將陣列容量縮小
  if (size == data.length / 2) {
    resize(data.length / 2);
  }
}

/***
 * 更新陣列大小
 * @param newCapacity
 */
private void resize(int newCapacity) {
    E[] newData = (E[]) new Object[newCapacity];
    for (int i = 0; i < size; i ++) {
        newData[i] = data[i];
    }

    data = newData;
}
複製程式碼

avatar

相關文章