Data Structures | 连载 01 - 动态数组 ArrayList 实现(二)

简介: Data Structures | 连载 01 - 动态数组 ArrayList 实现

add()方法重写,在具体位置增加元素

// 在具体位置增加元素
public void add(int index, int element){
    // 首先判断索引,index可以等于size,相当于在末尾添加元素
    if (index < 0 || index > size){
        throw new IndexOutOfBoundsException("index=" + index + ",size=" + size);
    }
    // 要在指定索引增加元素,要现将这个索引位置及之后的元素往后移动一个索引,腾出位置
    // 挪动元素,从最后一个开始挪动,否则后一个元素会被前一个元素覆盖
    for (int i = size - 1; i > index; i--) {
        elements[i + 1] = elements[i];
    }
    elements[index] = element;
    // 增加size
    size ++;
}
复制代码

测试

@Test
public void add() {
    System.out.println(arrayList.toString());
    arrayList.add(9);
    System.out.println(arrayList.toString());
    arrayList.add(2,11);
    System.out.println(arrayList.toString());
}
复制代码

0表示数组中空闲的位置

image.png

add(int element)可以优化为

public void add(int element){
    // 数组末尾添加元素
    add(size,element);
}
复制代码

解决数组的致命弱点-无法动态扩容

如果数组的容量快被占满,则需要向内存申请一块空间用来保存数据,让变量指向新的内存空间,原来的内存空间没有变量指向,将会被回收,回收前需要将原数组中的数据拷贝到新的数组中,并且新数组的容量相应扩展2倍或者一个根据使用情况适合的倍数

增加一个扩容函数

// 扩容方式一,使用指定扩容,方法中自行作判断何时需要扩容,调用时传入扩容的大小
private void expansionCapacity(int newCapacity){ 
    int oldCapacity = elements.length;
    if (oldCapacity >= size + 1) return;
    // 创建一个新的容量的数组
    // newCapacity = oldCapacity + (oldCapacity >> 1);
    int[] newElements = new int[newCapacity];
    // 拷贝元素
    for (int i = 0; i < size; i++) {
        newElements[i] = elements[i];
    }
    // 指向新的内存空间
    elements = newElements;
    System.out.println("扩容成功,由" + oldCapacity + "扩展至" + newCapacity);
}
复制代码

在add(int index, int element)方法中判断完index之后加入该方法

// 在具体位置增加元素
public void add(int index, int element){
    // 首先判断索引,index可以等于size,相当于在末尾添加元素
    if (index < 0 || index > size){
        throw new IndexOutOfBoundsException("index=" + index + ",size=" + size);
    }
    // 如果容量到达临界点会自动扩容,容量扩为原来的1.5倍
    expansionCapacity(elements.length + (elements.length >> 1));
    // 挪动元素,从最后一个开始挪动,否则后一个元素会被前一个元素覆盖
    for (int i = size - 1; i > index; i--) {
        elements[i + 1] = elements[i];
    }
    elements[index] = element;
    // 增加size
    size ++;
}
复制代码

再次进行优化

将判断索引抽取为工具类中的静态方法,新建utils包,增加工具类CheckUtils

public class CheckUtils {
    private static void outOfBoundary(int index,int size){
        throw new IndexOutOfBoundsException("index=" + index + ",size=" + size);
    }
    public static void checkIndex(int index, int size){
        if (index < 0 || index >= size){
            outOfBoundary(index, size);
        }
    }
    public static  void checkIndex4Add(int index, int size){
        if (index < 0 || index > size){
            outOfBoundary(index, size);
        }
    }
}
复制代码

最终BasicArrayList的代码为

public class BasicArrayList {
    // 元素的个数
    private int size;
    // 数组
    private int[] elements;
    private static final int DEFAULT_CAPATICY = 10;
    private static final int ELEMENT_NOT_FOUND = -1;
    public BasicArrayList(int capaticy){
        // 如果capaticy < 10 就使用默认的容量,否则使用自定义的容量
        capaticy = (capaticy < DEFAULT_CAPATICY) ? DEFAULT_CAPATICY : capaticy;
        elements = new int[capaticy];
    }
    public BasicArrayList(){
        elements = new int[DEFAULT_CAPATICY];
    }
    public int size(){
        return size;
    }
    public boolean isEmpty(){
        return size == 0;
    }
    public int get(int index){
        CheckUtils.checkIndex(index,size);
        return elements[index];
    }
    public int set(int index, int element){
        CheckUtils.checkIndex(index,size);
        int old = elements[index];
        elements[index] = element;
        return old;
    }
    public int indexOf(int element){
        for (int i = 0; i < size; i++) {
            if (elements[i] == element) return i;
        }
        return ELEMENT_NOT_FOUND;
    }
    public boolean contains(int element){
        return indexOf(element) != ELEMENT_NOT_FOUND;
    }
    // 清空即无法访问任何一个元素
    public void clear(){
        size = 0;
    }
    public int remove(int index){
        // 首先判断index
        CheckUtils.checkIndex(index,size);
        int old = elements[index];
        // 只遍历需要挪动的部分,不需要遍历整个数组
        for (int i = index + 1; i < size; i++) {
            elements[i - 1] = elements[i];
        }
        size --;
        return old;
    }
    public void add(int element){
        // 数组末尾添加元素
        add(size,element);
    }
    // 在具体位置增加元素
    public void add(int index, int element){
        // 首先判断索引,index可以等于size,相当于在末尾添加元素
        CheckUtils.checkIndex4Add(index,size);
        // 增加一个元素,如果超过容量就扩容
        // 如果容量到达临界点会自动扩容,扩容1.5倍
        expansionCapacity(elements.length + (elements.length >> 1));
        // 挪动元素,从最后一个开始挪动,否则后一个元素会被前一个元素覆盖
        for (int i = size - 1; i > index; i--) {
            elements[i + 1] = elements[i];
        }
        elements[index] = element;
        // 增加size
        size ++;
    }
    // 方法中自行作判断,调用时传入扩大的容量
    private void expansionCapacity(int newCapacity){
        int oldCapacity = elements.length;
        if (oldCapacity >= size + 1) return;
        // 创建一个新的容量的数组
        // newCapacity = oldCapacity + (oldCapacity >> 1);
        int[] newElements = new int[newCapacity];
        // 拷贝元素
        for (int i = 0; i < size; i++) {
            newElements[i] = elements[i];
        }
        // 指向新的内存空间
        elements = newElements;
        System.out.println("扩容成功,由" + oldCapacity + "扩展至" + newCapacity);
    }
    private void ensureCapacity(int capacity){
        int oldCapacity = elements.length;
        if (oldCapacity >= capacity) return;
        // 创建一个新的容量的数组
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        int[] newElements = new int[newCapacity];
        // 拷贝元素
        for (int i = 0; i < size; i++) {
            newElements[i] = elements[i];
        }
        // 指向新的内存空间
        elements = newElements;
        System.out.println("扩容成功,由" + oldCapacity + "扩展至" + newCapacity);
    }
    @Override
    public String toString() {
        return "ArrayList{" +
                "size=" + size +
                ", elements=" + Arrays.toString(elements) +
                '}';
    }
}
复制代码

测试add

@Test
public void add() {
    System.out.println(arrayList.toString());
    arrayList.add(9);
    System.out.println(arrayList.toString());
    arrayList.add(2,11);
    System.out.println(arrayList.toString());
    arrayList.add(12);
    System.out.println(arrayList.toString());
}
复制代码

image.png


相关文章
|
1月前
|
存储 安全 Java
java集合框架及其特点(List、Set、Queue、Map)
java集合框架及其特点(List、Set、Queue、Map)
|
5月前
|
存储 算法 编译器
【霍洛维兹数据结构】数组和结构 | ARRAYS AND STRUCTURES | THE SPARSE MATRIX 稀疏矩阵
【霍洛维兹数据结构】数组和结构 | ARRAYS AND STRUCTURES | THE SPARSE MATRIX 稀疏矩阵
45 0
The LinkStNode for Linked stack | Data
The code in Data book (5th Edition) from the 83 page to 86 page
75 0
|
存储 安全 Java
Java集合-- Array List 与顺序表
Array List 与顺序表详解
|
存储 Java 测试技术
Data Structures | 连载 01 - 动态数组 ArrayList 实现(一)
Data Structures | 连载 01 - 动态数组 ArrayList 实现
Data Structures | 连载 01 - 动态数组 ArrayList 实现(一)
|
存储 索引
Data Structures | 连载 02 - 链表 LinkedList 实现(下)
Data Structures | 连载 02 - 链表 LinkedList 实现
Data Structures | 连载 02 - 链表 LinkedList 实现(下)
|
存储 索引
Data Structures | 连载 02 - 链表 LinkedList 实现(上)
Data Structures | 连载 02 - 链表 LinkedList 实现
Data Structures | 连载 02 - 链表 LinkedList 实现(上)
Data Structures (二) - 链表LinkedList实现(Part B)
Data Structures (二) - 链表LinkedList实现(Part B)
Data Structures (二) - 链表LinkedList实现(Part B)
Data Structures (三) - 栈Stack实现
Data Structures (三) - 栈Stack实现
Data Structures (三) - 栈Stack实现