Java 動態(tài)數(shù)組的實現(xiàn)示例
靜態(tài)數(shù)組
Java中最基本的數(shù)組大家肯定不會陌生:
int[] array = new int[6]; for (int i = 0; i < array.length; i++){ array[i] = 2 * i + 1; }
通過循環(huán)把元素放入指定的位置中,類似于這樣:
這是一個靜態(tài)數(shù)組,因為我們在第一步初始化的時候就已經(jīng)固定了它的長度,后面再也無法改變。所以,由于有這個限制,靜態(tài)數(shù)組不適用于那些不確定儲存多少數(shù)據(jù)的場景。
但是如果數(shù)組滿了,能否再新建一個更長一些的數(shù)組,把原數(shù)組這些元素再轉(zhuǎn)移到新數(shù)組中呢?這樣一來,數(shù)組就可以繼續(xù)使用了。按照這個思路,我們就可以創(chuàng)建基于靜態(tài)數(shù)組的動態(tài)數(shù)組。
動態(tài)數(shù)組的實現(xiàn)原理
“動態(tài)”主要體現(xiàn)在以下幾方面:
1.添加元素
不局限于只在數(shù)組末尾添加,而是能夠隨意選擇索引位置(只要不超過數(shù)組長度)。例如在索引為1處添加元素4:
從圖中可以看出,需要將index處及右側(cè)的元素依次向右移動一個單位(從末位元素開始),最后用新增元素覆蓋index處元素。
2.刪除元素
同添加元素,也可根據(jù)索引進行選擇。例如刪除索引為0處的元素3:
刪除元素移動元素的方向與添加元素正好相反,從index處開始,直接使用后一位元素覆蓋前一位元素,最后將末位元素置為null。
3.數(shù)組擴容
數(shù)組一旦裝滿元素,可觸發(fā)數(shù)組擴容,即新建一個更長的數(shù)組,將原數(shù)組元素轉(zhuǎn)移到新數(shù)組中,并將引用指向新數(shù)組,完成數(shù)組的變更;
4.數(shù)組縮減
如果數(shù)組元素相對總?cè)萘縼碚f過少(例如數(shù)組元素個數(shù)小于數(shù)組容量的1/4),便可觸發(fā)數(shù)組縮減,即新建一個更短的數(shù)組,并轉(zhuǎn)移元素至新數(shù)組。
代碼實現(xiàn)
以下通過新建一個 Array 類,依次實現(xiàn)這幾個重要功能:
public class Array<E> { private E[] data; // 使用靜態(tài)數(shù)組存放數(shù)組元素 private int size; // 記錄數(shù)組元素數(shù)量 public Array(int capacity) { this.data = (E[]) new Object[capacity]; this.size = 0; } public Array() { this(10); // 默認capacity為10 } // 數(shù)組擴容/縮減 public void resize(int newCapacity) { // 新數(shù)組長度必須大于0 if (newCapacity < 0) throw new IllegalArgumentException("capacity must > 0!"); // 創(chuàng)建新數(shù)組 E[] newData = (E[]) new Object[newCapacity]; // 將原數(shù)組元素放入新數(shù)組中 for (int i = 0; i < size; i++) { newData[i] = data[i]; } // 將引用指向新數(shù)組 data = newData; } /** * 在指定位置添加元素 * 指定位置處的元素需要向右側(cè)移動一個單位 * @param index 索引 * @param element 要添加的元素 */ public void add(int index, E element) { if (index < 0 || index > size) throw new IllegalArgumentException("Illegal index, index must > 0 and <= size!"); // 數(shù)組滿員觸發(fā)擴容 if (size == data.length) { resize(2 * data.length); // 擴容為原數(shù)組的2倍 } // 從尾部開始,向右移動元素,直到index for (int i = size - 1; i >= index; i--) { data[i + 1] = data[i]; } // 添加元素 data[index] = element; size++; } // 數(shù)組頭部添加元素 public void addFirst(E element) { add(0, element); } // 數(shù)組尾部添加元素 public void addLast(E element) { add(size, element); } /** * 刪除指定位置元素 * 通過向左移動一位,覆蓋指定位置處的元素,實現(xiàn)刪除元素(data[size - 1] = null) * @param index 索引 */ public E remove(int index) { if (index < 0 || index > size) throw new IllegalArgumentException("Illegal index, index must > 0 and < size!"); // 數(shù)組長度為0時拋出異常 if (size == 0) throw new IllegalArgumentException("Empty array!"); E removedElement = data[index]; // 向左移動元素 for (int i = index; i < size - 1; i++) { data[i] = data[i + 1]; } // 將尾部空閑出的位置置為空,釋放資源 data[size - 1] = null; size--; // size過小觸發(fā)數(shù)組縮減 if (size == data.length / 4 && data.length / 2 != 0) resize(data.length / 2); return removedElement; } // 刪除頭部元素 public E removeFirst() { return remove(0); } // 刪除尾部元素 public E removeLast() { return remove(size - 1); } // 重寫Override方法,自定義數(shù)組顯示格式 @Override public String toString() { StringBuilder str = new StringBuilder(); // 顯示數(shù)組的整體情況(長度、總?cè)萘? str.append(String.format("Array: size = %d, capacity = %d\n[", size, data.length)); // 循環(huán)添加數(shù)組元素至str for (int i = 0; i < size; i++) { str.append(data[i]); if (i < size - 1) str.append(", "); } str.append("]"); return str.toString(); } }
接下來我們測試一下這個數(shù)組的使用情況:
public static void main(String[] args) { // 添加10個元素 Array<Integer> arr = new Array<>(); for (int i = 0; i < 10; i++) arr.add(i, i); // 查看數(shù)組當前狀態(tài) System.out.println(arr); // 繼續(xù)添加元素,觀察是否擴容 arr.add(arr.size, 7); System.out.println(arr); // 再刪除6個元素,觀察是否縮減 for (int i = 0; i < 6; i++) { System.out.println("元素" + arr.removeFirst() + "已被刪除!"); } System.out.println(arr); } /* 輸出結(jié)果: Array: size = 10, capacity = 10 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Array: size = 11, capacity = 20 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 7] 元素0已被刪除! 元素1已被刪除! 元素2已被刪除! 元素3已被刪除! 元素4已被刪除! 元素5已被刪除! Array: size = 5, capacity = 10 [6, 7, 8, 9, 7] */
可以看到,當數(shù)組滿員后,繼續(xù)添加元素可以成功觸發(fā)數(shù)組擴容;而當數(shù)組元素過少時,也會觸發(fā)縮減。
再實現(xiàn)幾個常用方法來完善我們的動態(tài)數(shù)組類:
// 獲取數(shù)組長度 public int getSize() { return size; } // 獲取數(shù)組總?cè)萘? public int getCapacity() { return data.length; } // 判斷數(shù)組是否為空 public boolean isEmpty() { return getSize() == 0; } // 查找指定元素在數(shù)組中的位置 public int search(E element) { for (int i = 0; i < getSize(); i++) { if (data[i].equals(element)) { return i; } } // -1表示未找到 return -1; } // 判斷指定元素是否在數(shù)組中 public boolean contains(E element) { return search(element) != -1; } // 按照索引查找元素值 public E get(int index) { if (index < 0 || index > size) throw new IllegalArgumentException("Illegal index, index must > 0 and < size!"); return data[index]; } // 查找頭部元素 public E getFirst() { return get(0); } // 查找尾部元素 public E getLast() { return get(getSize() - 1); } // 設(shè)置指定位置的元素值 public void set(int index, E element) { if (index < 0 || index > size) throw new IllegalArgumentException("Illegal index, index must > 0 and < size!"); data[index] = element; } /** * 按照元素值刪除 * 只刪除數(shù)組中第一個元素值與指定值相等的元素 * @param element 指定元素值 */ public boolean removeElement(E element) { int index = search(element); if (index != -1) { remove(index); return true; } return false; } /** * 按照元素值刪除 * 刪除數(shù)組中所有值與指定值相等的元素 * * @param element 指定元素值 */ public boolean removeElementAll(E element) { boolean isRemoved = false; int i = getSize() - 1; while (i >= 0) { if (data[i].equals(element)) { remove(i); isRemoved = true; } i--; } return isRemoved; }
從外部調(diào)用者的角度,無法覺察到其中的數(shù)組變更操作,感覺就是一個動態(tài)數(shù)組,但是由于擴容和縮減操作均需要新建數(shù)組,并且遍歷原數(shù)組,會導(dǎo)致過多的開銷,所以從性能上來說,并不是好的解決方案。后面我們將學(xué)習(xí)更加高效的數(shù)據(jù)結(jié)構(gòu)。
到此這篇關(guān)于Java 動態(tài)數(shù)組的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)Java 動態(tài)數(shù)組內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Profile與PropertyPlaceholderConfigurer項目多環(huán)境配置切換
這篇文章主要介紹了Spring Profile與PropertyPlaceholderConfigurer項目多環(huán)境配置切換方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09java并發(fā)編程StampedLock高性能讀寫鎖詳解
這篇文章主要為大家介紹了java并發(fā)編程StampedLock高性能讀寫鎖的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05將InputStream轉(zhuǎn)化為base64的實例
這篇文章主要介紹了將InputStream轉(zhuǎn)化為base64的實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12java簡單實現(xiàn)復(fù)制 粘貼 剪切功能代碼分享
本文給大家分享了一段java編寫的簡單實現(xiàn)復(fù)制粘貼剪切功能的代碼,需要的小伙伴可以直接拿走使用。如有更好的方案,也可以告之本人。2014-11-11SpringBoot+mybatis+Vue實現(xiàn)前后端分離項目的示例
本文主要介紹了SpringBoot+mybatis+Vue實現(xiàn)前后端分離項目的示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12Java讀取制表符文本轉(zhuǎn)換為JSON實現(xiàn)實例
在Java開發(fā)中,處理各種數(shù)據(jù)格式是常見的任務(wù),本文將介紹如何使用Java讀取制表符文本文件,并將其轉(zhuǎn)換為JSON格式,以便于后續(xù)的數(shù)據(jù)處理和分析,我們將使用Java中的相關(guān)庫來實現(xiàn)這個過程,并提供詳細的代碼示例2024-01-01