自动管理容量的线性表——动态数组(ArrayList)

设计背景

传统的数组在声明时必须确定大小,一旦创建便不能再改变容量。如果需要增大/缩小容量的话,则需要手动创建一个新数组,然后再将旧数组的内容拷贝至新数组,从而完成扩容/缩容。动态数组(ArrayList)的数据结构将这一系列操作进行了封装,只向用户提供的相应的方法(增删改查),提高了数组的利用效率。
在这里插入图片描述


结构分析

【结构类型】线性结构
【底层实现】数组(Array)
【核心方法】
public void add(int index, E e); // 向指定索引处添加元素
public E remove(int index); // 删除指定索引处的元素
private void resize(int newCapacity); // 调整数组容量的方法


代码实现

public class ArrayList<E> {

    /**
     * 实例域:数组、元素个数
     */
    private E[] data;
    private int size;

    /**
     * 带参构造器:对实例域进行初始化
     * @param capacity 数组容量
     */
    public ArrayList(int capacity) {
        data = (E[]) new Object[capacity]; // 注:Java不支持new泛型数组对象
        size = 0;
    }

    /**
     * 无参构造器:利用带参构造器进行初始化,默认容量20
     */
    public ArrayList() {
        this(20);
    }

    /**
     * 方法:获取数组容量
     * @return 数组容量
     */
    public int getCapacity() {
        return data.length;
    }

    /**
     * 方法:获取数组元素个数
     * @return 元素个数
     */
    public int getSize() {
        return size;
    }

    /**
     * 方法:判断数组是否为空
     * @return 为空时返回ture,反之false
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 方法:向指定索引处添加元素
     * @param index 索引
     * @param e 元素
     */
    public void add(int index, E e) {
        // 判断索引是否有效
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("Index is illegal!");
        }
        // 当数组满时,进行扩容操作,新数组的容量为原来的2倍
        if (size == data.length) {
            resize(data.length * 2);
        }
        // 将索引处及其后方的所有元素均后移一位,给新元素腾出空间
        for (int i = size - 1; i >= index; i--) {
            data[i + 1] = data[i];
        }
        // 将元素添加到指定位置
        data[index] = e;
        // 元素个数加一
        size++;
    }

    /**
     * 方法:向数组头添加元素
     * @param e 元素
     */
    public void addFirst(E e) {
        add(0, e);
    }

    /**
     * 方法:向所有数组末尾添加元素
     * @param e 元素
     */
    public void addLast(E e) {
        add(size, e);
    }

    /**
     * 方法:移除指定索引处的元素
     * @param index 索引
     * @return 被删除的元素
     */
    public E remove(int index) {
        // 判断索引是否有效
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("Index is illegal!");
        }
        // 将待删除的元素存入临时变量中
        E ret = data[index];
        // 将索引处后方的元素前移
        for (int i = index + 1; i < size; i++) {
            data[i - 1] = data[i];
        }
        // 数组元素数减一
        size--;
        // 手动释放末尾闲置元素(可选)
        data[size] = null;
        // 当数组3/4的空间为空时,进行缩容操作,新数组的容量为原来的一半
        if (size == data.length / 4 && data.length != 0) {
            resize(data.length / 2);
        }
        // 返回临时变量
        return ret;
    }

    /**
     * 方法:移除数组头部的元素
     * @return 被删除的元素
     */
    public E removeFirst() {
        return remove(0);
    }

    /**
     * 方法:移除数组尾部的元素
     * @return 被删除的元素
     */
    public E removeLast() {
        return remove(size - 1);
    }

    /**
     * 方法:调整数组容量
     * @param newCapacity 新数组的容量
     */
    private void resize(int newCapacity) {
        // 创建新数组
        E[] newData = (E[]) new Object[newCapacity];
        // 将旧数组的数据拷贝至新数组
        for (int i = 0; i < size; i++) {
            newData[i] = data[i];
        }
        // 将旧数组的变量引用到新数组
        data = newData;
    }

    /**
     * 方法:将指定索引处的元素替换为新元素
     * @param index 索引
     * @param e 新元素
     */
    public void set(int index, E e) {
        // 判断索引是否有效
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("Index is illegal!");
        }
        // 替换指定元素
        data[index] = e;
    }

    /**
     * 方法:判断数组是否包含某一元素
     * @param e 元素
     * @return 元素存在返回ture,反之返回false
     */
    public boolean contains(E e) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(e)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 方法: 返回指定索引处的元素
     * @param index
     * @return
     */
    public E get(int index) {
        // 判断索引是否有效
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("Index is illegal!");
        }
        // 返回指定元素
        return data[index];
    }

    /**
     * 方法:返回指定元素对应的索引
     * @param e 元素
     * @return 若元素存在返回索引,不存在返回-1
     */
    public int find(E e) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(e)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 覆写方法:将动态数组的信息作为字符串输出
     * @return 数组信息
     */
    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        res.append(String.format("ArrayList: size = %d, capacity = %d\n", size, data.length));
        res.append('[');
        for (int i = 0; i < size; i++) {
            res.append(data[i]);
            if (i != size - 1) {
                res.append(", ");
            }
        }
        res.append(']');
        return res.toString();
    }

}
发布了48 篇原创文章 · 获赞 4 · 访问量 6164

猜你喜欢

转载自blog.csdn.net/Knightletter/article/details/103118770
今日推荐