Java自定義一個(gè)變長(zhǎng)數(shù)組的思路與代碼
前言
首先需要聲明的是,Java
本身是提供了變長(zhǎng)數(shù)組的,即ArrayList
。那么自定義一個(gè)變長(zhǎng)數(shù)組有啥用?其實(shí)沒(méi)啥用或者說(shuō)用處不大,主要就是為了了解下變長(zhǎng)數(shù)組的設(shè)計(jì)理念而已。實(shí)際工作中直接使用ArrayList
。
思路分析
主要功能點(diǎn):
- 新建時(shí)可以指定容量大小,不指定時(shí)使用默認(rèn)容量大小。
- 向數(shù)組中追加新元素,當(dāng)超過(guò)容量時(shí)應(yīng)該自動(dòng)擴(kuò)容。
- 向數(shù)組中指定位置添加新元素,需要考慮指定的下標(biāo)是否越界,同樣也需要考慮擴(kuò)容操作。
- 刪除末尾的元素,需要考慮縮小容量。
- 刪除指定位置元素,需要考慮指定的下標(biāo)是否越界,同樣也需要考慮縮小容量。
- 修改特定位置的元素,需要考慮指定的下標(biāo)是否越界。
- 以時(shí)間復(fù)雜度為O ( 1 ) O(1)O(1)獲取任意位置的元素,需要考慮指定的下標(biāo)是否越界。
主要注意點(diǎn):
- 擴(kuò)容: 這里擴(kuò)容2倍(ArrayList 是擴(kuò)容 1.5 倍),擴(kuò)容時(shí)新建一個(gè)2倍容量的新數(shù)組,然后將舊數(shù)組中的元素按順序拷貝到新數(shù)組。
- 縮容: 當(dāng)數(shù)組中的元素個(gè)數(shù) <= 0.25 * 容量時(shí),自動(dòng)縮小容量為原來(lái)的一半,新建一個(gè)容量是原來(lái)容量一半的數(shù)組,然后將舊數(shù)組中的元素按順序拷貝到新數(shù)組。(ArrayList縮小為和當(dāng)前元素個(gè)數(shù)一樣大)。
- 指定位置添加: 需要先將指定位置及后面所有的元素都向后移動(dòng)一位,將指定位置空出來(lái)然后再插入。
- 指定位置刪除: 先將制定位置刪除,然后將后面的所有元素都向前移動(dòng)一位。
- 容量大?。?需要指定容量的最大值,避免OOM的發(fā)生。最小值可以指定也可以不指定。
實(shí)現(xiàn)代碼
/** * 變長(zhǎng)數(shù)組 * */ public class ResizeableArray<E> { private static final int MIN_CAPACITY = 10; private static final int MAX_CAPACITY = Integer.MAX_VALUE - 8; // 當(dāng)前實(shí)際數(shù)據(jù)大小 private int size = 0; // 實(shí)際存放元素的數(shù)組,容量為 elements.length private Object[] elements; public ResizeableArray(){ this(MIN_CAPACITY); } public ResizeableArray(int initCapacity){ if(initCapacity < MIN_CAPACITY){ initCapacity = MIN_CAPACITY; }else if(initCapacity > MAX_CAPACITY){ initCapacity = MAX_CAPACITY; } this.elements = new Object[initCapacity]; } // 數(shù)組的特性,根據(jù)下標(biāo)獲取元素 public E get(int index){ this.checkIndex(index); return (E)elements[index]; } // 添加一個(gè)元素到最后 public void add(E element){ if(size == elements.length){ // 需要擴(kuò)容 this.expandCapacity(); } elements[size++] = element; } // 添加一個(gè)元素到指定位置 public void add(int index, E element){ if(index == size){ this.add(element); return; } this.checkIndex(index); if(size == elements.length){ // 需要擴(kuò)容 this.expandCapacity(); } // 需要先將index和之后的所有元素向后移動(dòng)一位 for(int i = size - 1; i >= index; i--){ elements[i + 1] = elements[i]; } elements[index] = element; size++; } // 設(shè)置下標(biāo)為index的元素 private void set(int index, E element){ this.checkIndex(index); elements[index] = element; } /** * 刪除下標(biāo)為index的元素 * 當(dāng) size <= 0.25 * capacity 的時(shí)候縮小容量 */ private void delete(int index){ this.checkIndex(index); elements[index] = null; // 如果刪除的不是最后一個(gè)元素,需要將后續(xù)元素往前移動(dòng)一位 if(index < size - 1){ for(int i = index + 1; i < size; i++){ elements[i - 1] = elements[i]; } } size--; if(size <= 0.25 * elements.length){ this.reduceCapacity(); } } private void deleteLast(){ this.delete(size - 1); } private void checkIndex(int index){ if(index < 0 || index >= size){ throw new IndexOutOfBoundsException(String.format("Out of bounds at: %s, size is: %d", index, size)); } } private void expandCapacity(){ if(MAX_CAPACITY == elements.length){ // 容量達(dá)到最大限制,無(wú)法擴(kuò)容。 throw new RuntimeException("The capacity has reached its maximum limit and cannot be expanded."); } int newCapacity = Math.min(elements.length << 1, MAX_CAPACITY); Object[] newElements = new Object[newCapacity]; System.arraycopy(elements, 0, newElements, 0, size); elements = newElements; } private void reduceCapacity(){ if(elements.length == MIN_CAPACITY){ return; } int newCapacity = Math.max(elements.length >> 1, MIN_CAPACITY); Object[] newElements = new Object[newCapacity]; System.arraycopy(elements, 0, newElements, 0, size); elements = newElements; } public static void main(String[] args){ ResizeableArray<Integer> resizeableArray = new ResizeableArray<>(); System.out.printf("初始化后,size為: %d \n", resizeableArray.size); System.out.printf("初始化后,capacity為: %d \n", resizeableArray.elements.length); System.out.println(); for(int i = 0; i < 20; i++){ resizeableArray.add(i); } System.out.printf("添加20個(gè)元素后,size為: %d \n", resizeableArray.size); System.out.printf("添加20個(gè)元素后,capacity為: %d \n", resizeableArray.elements.length); System.out.printf("添加20個(gè)元素后,第5個(gè)元素是: %d \n", resizeableArray.get(4)); System.out.println(); resizeableArray.delete(4); System.out.printf("刪除第五個(gè)元素后,size為: %d \n", resizeableArray.size); System.out.printf("刪除第五個(gè)元素后,capacity為: %d \n", resizeableArray.elements.length); System.out.printf("刪除第五個(gè)元素后,第5個(gè)元素是: %d\n", resizeableArray.get(4)); System.out.println(); resizeableArray.add(4, 100); System.out.printf("在第五個(gè)位置插入元素后,size為: %d \n", resizeableArray.size); System.out.printf("在第五個(gè)位置插入元素后,capacity為: %d \n", resizeableArray.elements.length); System.out.printf("在第五個(gè)位置插入元素后,第5個(gè)元素是: %d\n", resizeableArray.get(4)); System.out.println(); for(int i = 0; i < 15; i++){ resizeableArray.deleteLast(); } System.out.printf("刪除后面15個(gè)元素后,size為: %d \n", resizeableArray.size); System.out.printf("刪除后面15個(gè)元素后,capacity為: %d \n", resizeableArray.elements.length); System.out.printf("刪除后面15個(gè)元素后,第5個(gè)元素是: %d\n", resizeableArray.get(4)); System.out.println(); resizeableArray.set(4, 200); System.out.printf("修改第五個(gè)元素后,當(dāng)前size為: %d \n", resizeableArray.size); System.out.printf("修改第五個(gè)元素后,capacity為: %d \n", resizeableArray.elements.length); System.out.printf("修改第五個(gè)元素后,第5個(gè)元素是: %d\n", resizeableArray.get(4)); } }
測(cè)試結(jié)果
由執(zhí)行結(jié)果可知:
- 初始化后默認(rèn)容量為
10
。 - 添加元素超過(guò)
10
個(gè)后會(huì)自動(dòng)擴(kuò)容。 - 刪除一個(gè)元素后,
size
會(huì)減1
,后面元素會(huì)自動(dòng)向前移動(dòng)一位。 - 插入一個(gè)新元素后,
size
會(huì)加1
,后續(xù)元素后移一位。 - 刪除到只有
0.25 * 容量
個(gè)元素后,會(huì)自動(dòng)縮小容量。
總結(jié)
到此這篇關(guān)于Java自定義一個(gè)變長(zhǎng)數(shù)組的思路與代碼的文章就介紹到這了,更多相關(guān)Java自定義變長(zhǎng)數(shù)組內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java基礎(chǔ)學(xué)習(xí)之Swing事件監(jiān)聽(tīng)
今天學(xué)習(xí)java的Swing庫(kù),創(chuàng)建桌面應(yīng)用的時(shí)候,突然發(fā)現(xiàn)有些按鈕需要特定的功能響應(yīng),故來(lái)研究一番Swing的事件監(jiān)聽(tīng),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-05-05mybatis多對(duì)多關(guān)聯(lián)實(shí)戰(zhàn)教程(推薦)
下面小編就為大家?guī)?lái)一篇mybatis多對(duì)多關(guān)聯(lián)實(shí)戰(zhàn)教程(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10基于Eclipce配置Spring Boot過(guò)程圖解
這篇文章主要介紹了基于Eclipce配置Spring Boot過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03關(guān)于java編譯過(guò)程中的bug說(shuō)明
本篇文章是對(duì)java編譯過(guò)程中的bug進(jìn)行了詳細(xì)的說(shuō)明介紹,需要的朋友參考下2013-05-05MyBatis攔截器動(dòng)態(tài)替換表名的方法詳解
因?yàn)槲覀兂志脤涌蚣芨嗟厥褂肕yBatis,那我們就借助于MyBatis的攔截器來(lái)完成我們的功能,這篇文章主要給大家介紹了關(guān)于MyBatis攔截器動(dòng)態(tài)替換表名的相關(guān)資料,需要的朋友可以參考下2022-04-04springboot?集成easy-captcha實(shí)現(xiàn)圖像驗(yàn)證碼顯示和登錄
本文主要介紹了springboot?集成easy-captcha實(shí)現(xiàn)圖像驗(yàn)證碼顯示和登錄,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04使用Java實(shí)現(xiàn)在Excel中添加動(dòng)態(tài)數(shù)組公式
動(dòng)態(tài)數(shù)組公式是?Excel?引入的一項(xiàng)重要功能,它允許用戶從單個(gè)單元格中的公式返回多個(gè)結(jié)果值,并將這些值自動(dòng)填充到與公式單元格相鄰的單元格中,本文主要介紹了如何使用Java實(shí)現(xiàn)在Excel中添加動(dòng)態(tài)數(shù)組公式,x需要的可以參考下2023-12-12