数据结构与算法(第一季):动态数组

2021-10-29  本文已影响0人  萧1帅

一、数组(Array)

image

二、动态数组(Dynamic Array)接口设计

image
public class ArrayList<E> {
    private int size;
    private E[] elements;

    // 元素的数量
    int size(); 
    // 是否为空
    boolean isEmpty();
    // 是否包含某个元素
    boolean contains(E element); 
    // 添加元素到最后面
    void add(E element); 
    // 返回index位置对应的元素
    E get(int index); 
    // 设置index位置的元素
    E set(int index, E element); 
    // 往index位置添加元素
    void add(int index, E element); 
    // 删除index位置对应的元素 
    E remove(int index); 
    // 查看元素的位置
    int indexOf(E element); 
    // 清除所有元素
    void clear(); 
}
复制代码

三、动态数组的实现

1、构造方法

public class ArrayList<E> {
    private int size;
    private E[] elements;
    // 设置elements数组默认的初始化空间
    private static final int CAPACITY_DEFAULT = 10;

    public ArrayList(int capacity) {
        capacity = capacity < CAPACITY_DEFAULT ? CAPACITY_DEFAULT : capacity;
        elements = (E[]) new Object[capacity];
    }

    // 便利构造器
    public ArrayList() {
        this(CAPACITY_DEFAULT);
    }
}
复制代码

2、添加元素

image
public void add(int index, E element) {
    elements[index] = element;
    size++;
}
复制代码
image
2.1、数组越界
private void rangeCheckForAdd(int index) {
    if (index < 0 || index > size) {
        outOfBounds(index);
    }
}
复制代码
2.2、数组扩容
image
private void ensureCapacity() {
    // 获取数组当前容量
    int oldCapacity = elements.length;
    // 如果 当前存储的元素个数 < 当前数组容量, 直接返回
    if (size < oldCapacity) return;
    // 新数组的容量为原数组容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 创建新数组
    E[] newElements = (E[]) new Object[newCapacity];
    // 原数组中的元素存储到新数组中
    for (int i = 0; i < size; i++) {
        newElements[i] = elements[I];
    }
    // 引用新数组
    elements = newElements;
}
复制代码
public void add(int index, E element) {
    //判断越界
    rangeCheckForAdd(index);
    //判断扩容          
    ensureCapacity(size + 1);

    for (int i = size; i > index; i--) {
        elements[i] = elements[i - 1];
    }
    elements[index] = element;
    size++;
}
复制代码
public void add(E element) {
    add(size, element);
}
复制代码

3、删除元素

image
3.1、数组越界

所以我们在删除元素之前需要先进行索引检查。

private void outOfBounds(int index) {
    throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}

private void rangeCheck(int index) {
    if (index < 0 || index >= size) {
        outOfBounds(index);
    }
}
复制代码
3.2、数组缩容
public void trim() {
    // 获取当前数组的容量
    int capacity = elements.length;
    // 当size大于等于容量的一半, 或则容量已经小于默认容量(10)时, 直接返回
    if (size >= capacity >> 1 || capacity < CAPACITY_DEFAULT) return;
    // 计算新的容量 = 原有容量的一半
    int newCapacity = capacity >> 1;
    // 创建新数组
    E[] newElements = (E[]) new Object[newCapacity];
    // 将原数组元素存入新数组
    for (int i = 0; i < size; i++) {
        newElements[i] = elements[I];
    }
    // 引用新数组
    elements = newElements;
}
复制代码
public E remove(int index) {
    // 判断索引是否越界
    rangeCheck(index);
    // 取出需要删除的元素
    E old = elements[index];
    // 通过循环, 将index后面的所有元素向前移动一位
    for (int i = index + 1; i < size; i++) {
        elements[i - 1] = elements[I];
    }
    // 删除最后一个元素
    elements[--size] = null;
    // 判断数组是否需要缩容
    trim();
    // 将删除的元素返回
    return old;
}
复制代码

4、清空数组

image
public void clear() {
    // 清空存储的数据
    for (int i = 0; i < size; i++) {
        elements[i] = null;
    }
    // 将size置为0
    size = 0;
}
复制代码

5、修改元素

public E set(int index, E element) {
    // 判断索引是否越界
    rangeCheck(index);
    // 取出被替换元素
    E oldElement = elements[index];
    // 替换元素
    elements[index] = element;
    // 返回被替换元素
    return oldElement;
}
复制代码

6、查询元素

public E get(int index) {
    rangeCheck(index);
    return elements[index];
}
复制代码

7、查看元素位置

private static final int ELEMENT_NOT_FOUND = -1;
public int indexOf(E element) {
    if (element == null) {
        for (int i = 0; i < size; i++) {
            if (elements[i] == null) return I;
        }
    } else {
        for (int i = 0; i < size; i++) {
            if (element.equals(elements[i])) return I;
        }
    }
    return ELEMENT_NOT_FOUND;
}
复制代码

8、是否包含某元素

public boolean contains(E element) {
    // 查看元素的索引是否为ELEMENT_ON_FOUND即可
    return indexOf(element) != ELEMENT_ON_FOUND;
}
复制代码

9、元素的数量

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

10、数组是否为空

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

11、动态数组打印

@Override
public String toString() {
    StringBuilder string = new StringBuilder();
    string.append("size = ").append(size).append(", [");
    for (int i = 0; i < size; i++) {
        if (i != 0) {
            string.append(",");
        }
        string.append(elements[I]);
    }
    string.append("]");
    return string.toString();
}
复制代码

到此为止,我们成功的实现了动态数组。

四、动态数组的复杂度

image

五、ArrayList能否进一步优化?

image image image image
上一篇 下一篇

猜你喜欢

热点阅读