【Data Structure and Algorithm】Simulate and implement ArrayList

Introduction to ArrayList

The ArrayList class is an array that can be dynamically modified. The difference from ordinary arrays is that it has no fixed size limit, and we can add or delete elements. ArrayList inherits from AbstractList and implements List interface.

Simply put, the bottom layer of ArrayList is a dynamic sequence table .
The bottom layer of the sequence table is the array.
Therefore, implementing ArrayList in a pattern is equivalent to implementing some operations based on the array, such as adding, deleting, checking, and modifying.

ArrayList simulation implementation

	public int[] elem;
    public int usedSize;//记录有效数据的个数
    //默认容量
    private static final int DEFAULT_SIZE = 10;
    public MyArraylist() {
    
    
        this.elem = new int[DEFAULT_SIZE];
    }

Put the data in the elem array, usedSize is used to calculate the number of valid data, and DEFAULT_SIZE is the default capacity of elem.

print sequence table

To print the sequence table, we can use a loop to print the data in the sequence table.

    /**
     * 打印顺序表:
     * 根据usedSize判断即可
     */
    public void display() {
    
    
        for (int i = 0; i < this.usedSize; i++) {
    
    
            System.out.print(this.elem[i] + " ");
        }
        System.out.println();
    }

Note: The effective data of elem in the sequence table is from [0,usedSize) , the entire array cannot be printed directly, and the data we store may not be able to fill the array.

Get the length of the sequence table

The length of the sequence table here is not the length of the underlying array, but the number of valid data in the array. Therefore, we can directly return usedSize

	public int size() {
    
    
        return this.usedSize;
    }

Determine if the current sequence table is full

To judge whether the current sequence table is full, you only need to check whether the usedSize (the number of valid data) is greater than or equal to the length of the underlying array. If it is full, return true. If it is not full, return false

    /**
     * 判断当前的顺序表是不是满的!
     */
    public boolean isFull() {
    
    
        if (size() >= this.elem.length) {
    
    
            return true;
        }
        return false;
        // 更简单的写法
        // return size() >= this.elem.length;
    }

Determine whether the current sequence table is empty

To judge whether the current sequence table is empty, just check whether the valid data in the sequence table is equal to 0

    //判断顺序表是否为空
    private boolean isEmpty() {
    
    
        return size()==0;
    }

Array expansion

Before adding elements, we have to think about what to do when the array is full. The sequence table is not a linked list, so there is no need to consider the situation of being full or dissatisfied, but the sequence table is different, and the length of the array is determined in advance.
如果数组长度设置的过大,而数据量很少,势必会造成空间的浪费.设置的过小,可能无法把所有元素存放进去.
For To avoid this situation, we can use a dynamic sequence table . Although it sounds very high, it is actually a process of dynamic expansion

扩容也并不复杂,使用Arrays.copyOf方法即可

数组名 = Arrays.copyOf(要拷贝的数组,拷贝数组的长度);

When copying, if the length of the array to be copied exceeds the original array, then the part exceeding the original array is the default value of the array type

Add new elements, by default at the end of the array

After solving the situation that the array is full, it is very simple to add elements. It is divided
into two steps: first, judge whether the array is full, and then expand the capacity. Then add elements. If it is not full, Add elements directly

    /** 新增元素,默认在数组最后新增
     * 判断顺序表是否满了
     * 满了->扩容
     * @param data
     */
    public void add(int data) {
    
    
        if (isFull()) {
    
    
            //扩容
            this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
        }
        this.elem[usedSize] = data;
        usedSize++;
    }

Add an element at the specified pos position

To add an element at a specified position, you must first determine whether the array is full, and if it is full, expand the capacity. Secondly, whether the position of pos is legal, and the element can be added at a legal position. Because the element is added from the specified position, if this position is not
in At the end, when adding an element, first move the elements at pos and beyond by one bit, and leave the position of pos empty, so that the element can be put in

    public void add(int pos, int data) {
    
    
        if(isFull()){
    
    
            this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
        }
        if(checkPos(pos)){
    
    
            for (int i = usedSize; i >= pos; i--) {
    
    
                this.elem[i] = this.elem[i-1];
            }
            this.elem[pos] = data;
        }
        this.usedSize++;
    }
    // 检查pos位置是否合法
    private boolean checkPos(int pos) {
    
    
        if (pos < 0 || pos > size()) {
    
    
            System.out.println("pos位置不合法");
            return false;
        }
        return true;//合法
    }

Determine whether an element is contained

Just traverse the array and compare it directly. If it is equal, return true directly. If there is no equal to it after traversing, return false

    // 判定是否包含某个元素
    public boolean contains(int toFind) {
    
    
        for (int i = 0; i < this.usedSize; i++) {
    
    
            if (toFind == this.elem[i]) {
    
    
                return true;
            }
        }
        return false;
    }

Find the position corresponding to an element

It is the same as judging whether an element is contained above, just traverse.
If equal, return the current i value, if not equal, continue to traverse. If not found after traversing, return -1

    // 查找某个元素对应的位置
    public int indexOf(int toFind) {
    
    
        for (int i = 0; i < this.usedSize; i++) {
    
    
            if (toFind == this.elem[i]) {
    
    
                return i;
             }
        }
            return -1;
    }

Get the element at the specified pos position

First check whether the sequence table is empty, if it is empty, return -1 directly. If it is not empty, then check whether the pos position is legal.
用自定义异常解决了顺序表为空这种情况,处理方法不一,合理即可

    // 获取 pos 位置的元素
    public int get(int pos) {
    
    
        if(isEmpty()){
    
    
            throw new EmptyException("顺序表为空!");
        }
        if(checkPos(pos)){
    
    
            return this.elem[pos];
        }
        return -1;
    }

Replace the element at the specified pos position with value

First judge whether the sequence table is empty, and then judge whether the pos position is legal. If it is satisfied, the value of the pos position can be updated to value

    // 给 pos 位置的元素设为【更新为】 value
    public void set(int pos, int value) {
    
    
        if(isEmpty()){
    
    
            throw new EmptyException("顺序表为空!");
        }
        if(pos < 0 || pos > size()){
    
    
            System.out.println("pos位置不合法");
            return;
        }
        this.elem[pos] = value;
    }

Delete the first occurrence of the keyword key

First judge whether the sequence table is empty, if it is empty, return directly,
then judge whether there is a key in the sequence table, if there is a key, directly let the elements behind the key position be overwritten one by one, if not, just return directly

    public void remove(int key) {
    
    
        if(isEmpty()){
    
    
            throw new EmptyException("顺序表为空!");
        }
        if(contains(key)) {
    
    
            int ret = indexOf(key);
            for (int i = ret; i < usedSize; i++) {
    
    
                this.elem[i] = this.elem[i+1];
            }
        }
        this.usedSize--;
    }

clear sequence table

public void clear() {
    
    
        this.usedSize = 0;
    }

The emptying here is not really emptying, but the previous elements will be overwritten when adding elements next time. If not overwritten, the original data still exists in the array. If you want to completely
clear the sequence table, you need to use Loop, set the array to 0 one by one

full code

main part:

import java.util.Arrays;

public class MyArrayList {
    
    

    public int[] elem;
    public int usedSize;//0//默认容量
    private static final int DEFAULT_SIZE = 10;

    public MyArrayList() {
    
    
        this.elem = new int[DEFAULT_SIZE];
    }

    /**
     * 打印顺序表:
     * 根据usedSize判断即可
     */
    public void display() {
    
    
        for (int i = 0; i < this.usedSize; i++) {
    
    
            System.out.print(this.elem[i] + " ");
        }
        System.out.println();
    }

    /** 新增元素,默认在数组最后新增
     * 判断顺序表是否满了
     * 满了->扩容
     * @param data
     */
    public void add(int data) {
    
    
        if (isFull()) {
    
    
            //扩容
            this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
        }
        this.elem[usedSize] = data;
        usedSize++;
    }

    /**
     * 判断当前的顺序表是不是满的!
     * @return true:满   false代表空
     */
    public boolean isFull() {
    
    
//        if (size() >= this.elem.length) {
    
    
//            return true;
//        }
//        return false;
        return size() >= this.elem.length;
    }


    private boolean checkPos(int pos) {
    
    
        if (pos < 0 || pos > size()) {
    
    
            System.out.println("pos位置不合法");
            return false;
        }
        return true;//合法
    }

    /** 在 pos 位置新增元素
     * 方法:将pos位置的元素向后移动
     * 情况:
     *  pos位置不合法
     *  不能间隔
     * @param pos
     * @param data
     *
     */
    public void add(int pos, int data) {
    
    
        if(isFull()){
    
    
            this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
        }
        if(checkPos(pos)){
    
    
            for (int i = usedSize; i >= pos; i--) {
    
    
                this.elem[i] = this.elem[i-1];
            }
            this.elem[pos] = data;
        }
        this.usedSize++;
    }

    // 判定是否包含某个元素
    public boolean contains(int toFind) {
    
    
        for (int i = 0; i < this.usedSize; i++) {
    
    
            if (toFind == this.elem[i]) {
    
    
                return true;
            } else {
    
    
                continue;
            }
        }
        return false;
    }

    // 查找某个元素对应的位置
    public int indexOf(int toFind) {
    
    
        for (int i = 0; i < this.usedSize; i++) {
    
    
            if (toFind == this.elem[i]) {
    
    
                return i;
             }
        }
            return -1;
    }

    // 获取 pos 位置的元素
    public int get(int pos) {
    
    
        if(isEmpty()){
    
    
            throw new EmptyException("顺序表为空!");
        }
        if(checkPos(pos)){
    
    
            return this.elem[pos];
        }
        return -1;
    }
    //判断顺序表是否为空
    private boolean isEmpty() {
    
    
        return size()==0;
    }

    // 给 pos 位置的元素设为【更新为】 value
    public void set(int pos, int value) {
    
    
        if(isEmpty()){
    
    
            throw new EmptyException("顺序表为空!");
        }
        if(pos < 0 || pos > size()){
    
    
            System.out.println("pos位置不合法");
            return;
        }
        this.elem[pos] = value;
    }

    /**
     * 删除第一次出现的关键字key
     * @param key
     */
    public void remove(int key) {
    
    
        if(isEmpty()){
    
    
            throw new EmptyException("顺序表为空!");
        }
        if(contains(key)) {
    
    
            int ret = indexOf(key);
            for (int i = ret; i < usedSize; i++) {
    
    
                this.elem[i] = this.elem[i+1];
            }
        }
        this.usedSize--;
    }

    // 获取顺序表长度
    public int size() {
    
    
        return this.usedSize;
    }

    // 清空顺序表
    public void clear() {
    
    
        this.usedSize = 0;
    }
}

custom exception section

public class EmptyException extends RuntimeException{
    
    
    public EmptyException() {
    
    

    }

    public EmptyException(String message) {
    
    
        super(message);
    }
}

Guess you like

Origin blog.csdn.net/m0_63463510/article/details/127325250