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)文章
spring boot配置多個(gè)請(qǐng)求服務(wù)代理的完整步驟
這篇文章主要給大家介紹了關(guān)于spring boot配置多個(gè)請(qǐng)求服務(wù)代理的完整步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
springcloud-feign調(diào)用報(bào)錯(cuò)問(wèn)題
這篇文章主要介紹了springcloud-feign調(diào)用報(bào)錯(cuò)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
Spring Data Jpa 復(fù)合主鍵的實(shí)現(xiàn)
這篇文章主要介紹了Spring Data Jpa 復(fù)合主鍵的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
SpringBoot實(shí)現(xiàn)文件上傳下載實(shí)時(shí)進(jìn)度條功能(附源碼)
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何實(shí)現(xiàn)文件上傳下載實(shí)時(shí)進(jìn)度條功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下2022-10-10
詳解關(guān)于Windows10 Java環(huán)境變量配置問(wèn)題的解決辦法
這篇文章主要介紹了關(guān)于Windows10 Java環(huán)境變量配置問(wèn)題的解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
MyBatis實(shí)現(xiàn)多表聯(lián)查的詳細(xì)代碼
這篇文章主要介紹了MyBatis如何實(shí)現(xiàn)多表聯(lián)查,通過(guò)實(shí)例代碼給大家介紹使用映射配置文件實(shí)現(xiàn)多表聯(lián)查,使用注解的方式實(shí)現(xiàn)多表聯(lián)查,需要的朋友可以參考下2022-08-08
Java實(shí)現(xiàn)Dijkstra算法的示例代碼
Dijkstra(迪杰斯特拉)算法是典型的單源最短路徑算法,用于計(jì)算一個(gè)節(jié)點(diǎn)到其他所有節(jié)點(diǎn)的最短路徑。本文主要介紹了實(shí)現(xiàn)這一算法的Java代碼,需要的可以參考一下2022-07-07
Spring Bean創(chuàng)建和循環(huán)依賴
這篇文章主要介紹了Spring Bean創(chuàng)建和循環(huán)依賴,講述了Spring容器中?Bean?的創(chuàng)建過(guò)程已經(jīng)主要的方法,另外也著重分析了循環(huán)依賴的問(wèn)題,需要的小伙伴可以參考一下2022-05-05
java中建立0-10m的消息(字符串)實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇java中建立0-10m的消息(字符串)實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05

