Java版-資料結構-陣列

小白程式之路發表於2019-03-11

陣列知識點回顧

宣告Java陣列時,會在記憶體中開闢一塊連續指定大小的空間,用來儲存固定大小的同型別元素

在java中定義個名為scores,長度為8,型別為int型別的陣列如下:

public static void main(String[] args) {
    int[] scores = new int[8];
}
複製程式碼

為了便於理解,我們看下它在記憶體的中的分佈示意圖:

1

圖中的一個個小格子是用來存放陣列的元素,小格子上方的0-7數字,是陣列中每個元素的下標(也可以叫索引),如果我們要查詢陣列中指定位置的元素,我們可以通過陣列名[索引]來獲取,比如圖中的scores[2]

在圖中我們還可以看到,陣列的起始下標是從0開始的(也就是第一個元素),最後一個元素的下標是7(也就是陣列的長度81)由此類推,陣列長度若是n,那麼陣列最後一個元素的下標是n-1(陣列的起始下標總是從0開始的)

各位不要閒嘮叨哈,為了照顧所有人(其實我的內心是很糾結的。。。?)

自定義陣列類

思路分析

使用data屬性表示存放陣列的元素,

使用capacity屬性表示陣列的容量(等價於陣列的長度),但是真正自定義陣列類的時候我們不需要顯示宣告,因為隱示等價於(Array.length

使用size屬性表示陣列中真正存放元素的個數(注意和capacity概念的區分)。

我們畫出示意圖:

image-20190310023248174

下面我們來完成初始程式碼

public class ArrayExample {
    /**
     * 存放陣列的元素
     */
    private int data[];

    /**
     * 陣列中元素的個數
     */
    private int size;

    /**
     * 根據指定capacity容量初始化陣列
     *
     * @param capacity 容量
     */
    public ArrayExample(int capacity) {
        data = new int[capacity];
        size = 0;
    }

    /**
     * 無參建構函式,指定預設陣列容量capacity=10
     */
    public ArrayExample() {
        this(10);
    }

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

    /**
     * 獲取陣列容量
     *
     * @return
     */
    public int getCapacity() {
        return data.length;
    }
}
複製程式碼

向陣列中新增元素

向指定位置新增元素

假設現在陣列的形態是這樣,我們需要將77元素插入到索引為1的位置

image-20190310030112445

思路分析:把當前索引為1的位置元素以及後面的元素都向後挪一個位置,然後將77這個元素放到索引為1的位置(注意:挪位置的時候,我們應該從最後一個元素100向後挪一個位置,換句話說從後往前挪),完成之後,維護一下size的索引,進行size++操作(size是始終指向陣列中下一個沒有元素的位置)

image-20190310031102611

下面我們基於前面寫的程式碼,來完成陣列元素的新增操作

/**
  * 在index位置插入元素
  *
  * @param index   指定索引
  * @param element 插入的元素
  */
public void add(int index, int element) {
    // 簡單的邊界判斷
    if (size == data.length) {
        throw new IllegalArgumentException("陣列新增失敗,陣列已滿");
    }
    if (index < 0 || index > size) {
        throw new IllegalArgumentException("index索引不合法");
    }

    // 從最後一個元素一直到size位置的元素,往後挪動一位
    for (int i = size - 1; i >= index; i--) {
        data[i + 1] = data[i];
    }

    // 位置賦值
    data[index] = element;

    // 維護size大小
    size++;
}

複製程式碼

由於方面大家檢視,只貼出新增陣列元素的程式碼,本文文末,會貼出完成的程式碼示例地址

現在如果我們想把一個元素新增到陣列頭部的位置或者尾部的位置,我們可以這麼做

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

/**
  * 向陣列尾的位置新增元素
  *
  * @param element 元素
  */
public void addLast(int element) {
    add(size, element);
}
複製程式碼

大家一定要注重程式碼的複用性哈

查詢陣列元素和修改陣列元素

查詢陣列元素
/**
  * 獲取index索引位置的元素
  *
  * @param index 索引
  * @return
  */
public int get(int index) {
    if (index < 0 || index >= size) {
        throw new IllegalArgumentException("獲取失敗,索引不合法");
    }
    return data[index];
}
複製程式碼
修改陣列元素
/**
  * 修改index索引位置的元素為element
  *
  * @param index   索引
  * @param element 元素
  */
public void set(int index, int element) {
    if (index < 0 || index >= size) {
        throw new IllegalArgumentException("獲取失敗,索引不合法");
    }
    data[index] = element;
}
複製程式碼

包含陣列元素和搜尋陣列元素

包含陣列元素
/**
  * 查詢陣列中是否有元素element
  *
  * @param element
  * @return
  */
public boolean contains(int element) {
    return Arrays.stream(data).filter(x -> x == element).findAny().isPresent();
}
複製程式碼

這裡使用了Java8的lambda表示式,不知曉的盆友,可以自行去了解一下

搜尋陣列元素
/**
  * 查詢陣列中元素element所在的索引,如果不存在元素element,則返回-1
  *
  * @param element
  * @return
  */
public int find(int element) {
    for (int i = 0; i < data.length; i++) {
        if (data[i] == element) {
            return i;
        }
    }
    return -1;
}
複製程式碼

刪除陣列中的元素

現在我們要刪除索引為1的元素77

image-20190310154244026

思路分析:我們知曉了陣列的插入思路,那麼陣列的刪除思路,剛好和陣列的插入思路相反,如果要刪除索引為1位置的元素77,我們只需要,從索引2開始,將索引2位置的元素向移動到索引為1的位置,也就是將索引2位置的元素的值賦值給索引為1位置的元素(等價於data[1]=data[2]),依次類推,將索引為3位置的元素,移動到索引為2位置的元素,一直到最後一個元素,比如圖中的元素100,完成之後,這時候,我們需要再次維護一下size的大小,我們要進行size--操作

重要 size 既表示陣列中元素的大小,又表示始終指向陣列中第一個沒有元素的位置

程式碼完成陣列的刪除操作

/**
  * 刪除索引index位置的元素,並將刪除的元素返回
  *
  * @param index
  * @return
  */
public int remove(int index) {
    // 簡單判斷陣列索引的合法性
    if (index < 0 || index >= size) {
        throw new IllegalArgumentException("刪除陣列元素失敗,索引不合法");
    }
    
    // 存放刪除指定索引的位置元素
    int result = data[index];
    
    // 從刪除指定索引的後一個位置,一直往前挪一位,直到最後一個元素
    for (int i = index + 1; i < size; i++) {
        data[i - 1] = data[i];
    }
    
    // 維護size的位置
    size--;
    return result;
}
複製程式碼

完成了陣列元素的刪除操作,我們還可以便捷地為陣列新增刪除陣列中第一個元素的方法和刪除陣列中最後一個元的方法。

刪除陣列中第一個元素的方法

/**
  * 刪除陣列中第一個元素,並將刪除的元素進行返回
  *
  * @return
  */
public int removeFirst() {
    return remove(0);
}
複製程式碼

刪除陣列中最後一個元素的方法

/**
  * 刪除陣列中最後一個元素,並將刪除的元素進行返回
  *
  * @return
  */
public int removeLast() {
    return remove(size - 1);
}
複製程式碼

至此,我們已經完成了陣列的增刪改查操作,下面我們寫個測試類,來使用一下我們自己寫的簡單版陣列

public class ArrayExampleTest {
    @Test
    public void testAdd() {
        // 初始化陣列容量大小為5,目前陣列中沒有任何元素
        ArrayExample arrayExample = new ArrayExample(5);
        System.out.println(arrayExample);

        // 向陣列中歐新增第一個元素
        arrayExample.addFirst(1);
        System.out.println(arrayExample);

        // 向陣列中新增最後一個元素
        arrayExample.addLast(2);
        System.out.println(arrayExample);

        // 向陣列中索引為0的位置新增元素
        arrayExample.add(0, 10);
        System.out.println(arrayExample);
    }

    // TODO 其它測試方法,讀者可以自行測試
}
複製程式碼

執行結果

ArrayExample{data=[0, 0, 0, 0, 0], size=0,capacity=5}
ArrayExample{data=[1, 0, 0, 0, 0], size=1,capacity=5}
ArrayExample{data=[1, 2, 0, 0, 0], size=2,capacity=5}
ArrayExample{data=[10, 1, 2, 0, 0], size=3,capacity=5}
複製程式碼

完整版程式碼GitHub倉庫地址:Java版資料結構-陣列 歡迎大家關注Star

本次我們完成的是靜態陣列的實現,往往靜態陣列不夠靈活,後面筆者會在程式碼倉庫中實現動態陣列,就不作為一個篇幅來講解了,接下來,筆者還會一一的實現其它常見的陣列結構。

  • 靜態陣列
  • 動態陣列
  • 佇列
  • 連結串列
  • 迴圈連結串列
  • 二分搜尋樹
  • 優先佇列
  • 線段樹
  • 字典樹
  • AVL
  • 紅黑樹
  • 雜湊表
  • ....

持續更新中,歡迎大家關注公眾號:小白程式之路(whiteontheroad),第一時間獲取最新資訊!!!

小白程式之路

部落格地址-->

相關文章