动态数组的实现(仿写ArrayList)

动态数组是什么

之前写过一篇数组和静态数组的介绍:数组的定义和特点,静态数组CURD的实现

我们在静态数组的基础上,增加一些比较方便的功能,比如自动扩容,获取数组长度等,这样的数组叫动态数组

动态数组的本质仍旧是静态数组,静态数组的特点它都有,只不过通过一些标记的变量新增了一些方法,方便我们进行CURD而已

相比于静态数组新增的功能

  1. 自动缩扩容
  2. addLast,add
  3. deleteLast,delete
  4. get,set(修改)
  5. size
  6. isEmpty

初始化动态数组

  1. 使用泛型可以创建任意类型的数组
  2. data即为真实的数组存放空间所在
  3. size是数组中存放数据的数量,初始为1
  4. INIT_CAPACITY 是默认的数组长度
  5. 提供了有参和无参构造
java 复制代码
public class MyDynamicArray<E> {
    private E[] data;// 数据

    private Integer size;// 数据容量

    private static final Integer INIT_CAPACITY = 10;// 初始容量


    public MyDynamicArray() {
        this(INIT_CAPACITY);
    }

    public MyDynamicArray(int initCapacity) {
        this.data = (E[]) new Object[initCapacity];
        this.size = 0;
    }

    public static void main(String[] args) {
        MyDynamicArray<Integer> dynamicArray = new MyDynamicArray<>();
        MyDynamicArray<String> dynamicArray2 = new MyDynamicArray<>(20);
    }
}

扩容/缩容

java 复制代码
    // 扩容/缩容
    public void resize(int newSize) {
        E[] newData = (E[]) new Object[newSize];
        int minSize = Math.min(this.size, newSize);
        for (int i = 0; i < minSize; i++) {
            newData[i] = this.data[i];
        }

        data = newData;
    }

add,addLast实现

java 复制代码
    // 尾部增
    public void addLast(E e) {
        int l = this.data.length;
        if (size == l) {
            resize(2 * l);
        }
        // 在尾部插入元素
        data[size] = e;
        size++;
    }
java 复制代码
    public void add(int index, E e) {
        // 判断index是否合法
        if (!isIndexValid(index)) {
            throw new IndexOutOfBoundsException();
        }
        int l = this.data.length;
        if (size == l) {
            resize(2 * l);
        }

        for (int i = size-1; i >= index; i--) {
            data[i+1] = data[i];
        }
        data[index] = e;
        size++;
    }

    public boolean isIndexValid(int index) {
        // 数组要保证元素连续,不能让两个元素之间有空位
        return index >= 0 && index < this.size;
    }

delete,deleteLast实现

java 复制代码
	// 删除尾部元素
    public E deleteLast() {
        if (size == 0) {
            throw new NoSuchElementException();
        }
        int l = data.length;
        // 可以缩容,节约空间
        if (size == l/ 4) {
            resize(l/ 2);
        }

        E deletedVal = data[size - 1];
        // 删除最后一个元素
        // 必须给最后一个元素置为 null,否则会内存泄漏
        data[size - 1] = null;
        size--;

        return deletedVal;
    }
java 复制代码
    // 删除中间元素
    public E delete(int index) {
        // 判断index是否合法
        if (!isIndexValid(index)) {
            throw new IndexOutOfBoundsException();
        }
        int l = this.data.length;
        // 缩容节约空间
        if (size == l / 4) {
            resize(l / 2);
        }
        E deletedVal = data[index];
        for (int j = index + 1; j < size; j++) {
            data[j - 1] = data[j];
        }
        data[size - 1] = null;
        size--;

        return deletedVal;
    }

get和set

java 复制代码
// 查询
    public E get(int index) {
        // 判断index是否合法
        if (!isIndexValid(index)) {
            throw new IndexOutOfBoundsException();
        }

        return data[index];
    }

    // 赋值
    public void set(int index, E newData) {
        // 判断index是否合法
        if (!isIndexValid(index)) {
            throw new IndexOutOfBoundsException();
        }

        data[index] = newData;
    }

size

java 复制代码
    public Integer size() {
        return size;
    }

isEmpty

java 复制代码
    public boolean isEmpty() {
        return size == 0;
    }

测试

java 复制代码
import java.util.Arrays;
import java.util.NoSuchElementException;

public class MyDynamicArray<E> {
    private E[] data;// 数据

    private Integer size;// 数据容量

    private static final Integer INIT_CAPACITY = 5;// 初始容量


    public MyDynamicArray() {
        this(INIT_CAPACITY);
    }

    public MyDynamicArray(int initCapacity) {
        this.data = (E[]) new Object[initCapacity];
        this.size = 0;
        System.out.print("===初始状态:");
        display();
    }

    // 扩容/缩容
    public void resize(int newSize) {
        E[] newData = (E[]) new Object[newSize];
        int minSize = Math.min(this.size, newSize);
        for (int i = 0; i < minSize; i++) {
            newData[i] = this.data[i];
        }

        data = newData;
        System.out.println("===旧size:" + this.size + ",新size:" + newSize);
        System.out.print("===扩容/缩容之后:");
        display();
    }


    // 尾部增
    public void addLast(E e) {
        int l = this.data.length;
        if (size == l) {
            resize(2 * l);
        }
        // 在尾部插入元素
        data[size] = e;
        size++;
        System.out.print("===尾插入后:");
        display();
    }

    public void add(int index, E e) {
        // 判断index是否合法
        if (!isIndexValid(index)) {
            throw new IndexOutOfBoundsException();
        }
        int l = this.data.length;
        if (size == l) {
            resize(2 * l);
        }

        for (int i = size - 1; i >= index; i--) {
            data[i + 1] = data[i];
        }
        data[index] = e;
        size++;
        System.out.print("===中间插入后:");
        display();
    }

    // 删除尾部元素
    public E deleteLast() {
        if (size == 0) {
            throw new NoSuchElementException();
        }
        int l = data.length;
        // 缩容节约空间
        if (size == l / 4) {
            resize(l / 2);
        }

        E deletedVal = data[size - 1];
        // 删除最后一个元素
        // 必须给最后一个元素置为 null,否则会内存泄漏
        data[size - 1] = null;
        size--;
        System.out.print("===尾删除后:");
        display();
        return deletedVal;
    }

    // 删除中间元素
    public E delete(int index) {
        // 判断index是否合法
        if (!isIndexValid(index)) {
            throw new IndexOutOfBoundsException();
        }
        int l = this.data.length;
        // 缩容节约空间
        if (size == l / 4) {
            resize(l / 2);
        }
        E deletedVal = data[index];
        for (int j = index + 1; j < size; j++) {
            data[j - 1] = data[j];
        }
        data[size - 1] = null;
        size--;
        System.out.print("===中间删除后:");
        display();
        return deletedVal;
    }

    // 查询
    public E get(int index) {
        // 判断index是否合法
        if (!isIndexValid(index)) {
            throw new IndexOutOfBoundsException();
        }

        return data[index];
    }

    // 赋值
    public void set(int index, E newData) {
        // 判断index是否合法
        if (!isIndexValid(index)) {
            throw new IndexOutOfBoundsException();
        }

        data[index] = newData;
        System.out.print("===修改后:");
        display();
    }

    public Integer size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean isIndexValid(int index) {
        // 数组要保证元素连续,不能让两个元素之间有空位
        return index >= 0 && index < this.size;
    }

    public void display() {
        System.out.println(Arrays.toString(data));
    }

    public static void main(String[] args) {
        MyDynamicArray<Integer> dynamicArray = new MyDynamicArray<>();
        dynamicArray.addLast(1);
        dynamicArray.addLast(2);
        dynamicArray.addLast(3);
        dynamicArray.addLast(4);
        dynamicArray.addLast(5);
        dynamicArray.addLast(6);
        dynamicArray.add(2, 100);
        dynamicArray.deleteLast();
        dynamicArray.delete(3);
        System.out.println("===get方法结果:" + dynamicArray.get(3));
        dynamicArray.set(2,666);
        dynamicArray.deleteLast();
        dynamicArray.deleteLast();
        dynamicArray.deleteLast();
        dynamicArray.deleteLast();
    }
}

运行结果

我们可以很清楚的看到扩容和缩容,删除和新增等操作的实现

相关推荐
ZHE|张恒20 小时前
LeetCode - 寻找两个正序数组的中位数
算法·leetcode
华仔啊20 小时前
为什么你的 @Transactional 不生效?一文搞懂 Spring 事务机制
java·后端
Lacrimosa&L20 小时前
OS_3 Memory、4 File、5 IO
java
爱学的小码20 小时前
JavaEE——多线程1(超详细版)
java·java-ee
小龙报20 小时前
《算法通关指南算法千题篇(5)--- 1.最长递增,2.交换瓶子,3.翻硬币》
c语言·开发语言·数据结构·c++·算法·学习方法·visual studio
tuokuac20 小时前
依赖spring-cloud-starter-gateway与spring-cloud-gateway-dependencies的区别
java·gateway
Cx330❀20 小时前
《C++ 多态》三大面向对象编程——多态:虚函数机制、重写规范与现代C++多态控制全概要
开发语言·数据结构·c++·算法·面试
_dindong20 小时前
【递归、回溯、搜索】专题六:记忆化搜索
数据结构·c++·笔记·学习·算法·深度优先·哈希算法
seabirdssss20 小时前
JDK 11 环境正确,端口未被占用,但是运行 Tomcat 11 仍然闪退
java·开发语言·tomcat
努力学算法的蒟蒻21 小时前
day03(11.1)——leetcode面试经典150
java·算法·leetcode