【数据结构】手动实现基础数据结构_ArrayList

学习数据结构,必不可少的就是手动实现它们,亲自动手做了,才可以真正理解。

 

ArrayList,顾名思义,是用数组实现的链表,一个链表的基本功能可以说是增删查改,对于数组来说,查询、修改是非常容易的,直接通过数组的下标就可以完成,时间复杂度是常数级别的。而添加、删除就比较麻烦,为了保证数据的连续性,数组之间不可以有"空位"(即没有存放有效数据的空间),那么在添加删除时需要将数组移位,最好的情况是添加删除都在链表的末尾,时间复杂度为O(c),但最坏的情况是在链表的头部添加删除数据,时间复杂度为O(n),综合来算,时间复杂度为O(n)

 

如下图,如果要删除a[3]的数据,那么删除之后,a[3]以后的数据都要向前移动一位,以保证数据的有效性,添加同理

 

除了增删查改,还应该能获取到链表的大小、清空链表、判断链表是否为空等操作。此外,链表还应该具有自动扩容的功能,使用链表的人不需要操心链表的大小是否够用,若添加的数据超出了数组的容量,应自动扩容。

 

 

添加数据:有两种方法,一是在链表末尾添加数据,二是在链表中插入数据,这两种实际上可以概括为在链表的某一个位置插入数据。在添加数据之前,首先要判断现有数据的大小是否超出了数组的容量,若超出,则需要扩容,否则插入数据。

 

/**
 * 在链表末尾添加元素
 * 
 * @param e
 * @return
 */
public boolean add(Object e) {
    // 判断是否需要扩容
    if(size == list.length){
        ensureCapacity();
    }
    list[size++] = e;
    return true;
}

/**
 * 在指定下标位置添加元素
 * 
 * @param e     要添加的元素
 * @param index 下标
 * @return
 */
publicboolean add(Object e, int index) {
    // 下标越界,抛出异常
    if (index > size || index < 0) {
        throw new ArrayIndexOutOfBoundsException(index);
    }
    // 判断是否需要扩容
    if(size == list.length){
        ensureCapacity();
    }
    // 在末尾添加数据
    if (index == size) {
        return add(e);
    }
    for (int i = size - 1; i >= index; i--) {
        list[i + 1] = list[i];
    }
    list[index] = e;
    size++;
    return true;
}    

/**
 * 扩容
 */
private void ensureCapacity() {
    Object[] newList = new Object[(int) (size + 0.5 * size)];
    // native方法,提高效率
    System.arraycopy(list, 0, newList, 0, list.length);
    list = newList;
    }
}

 

删除数据:与添加数据一样,也有两种方法,不带参数的方法默认删除链表最后一个数据,带参数的则删除参数指定的数据

/**
 * 删除元素,参数为空则删除最后一个
 */
public Object remove() {
    if(size <= 0) {
        return null;
    }
    Object o = get(size-1);
    size --;
    return o;
}

/**
 * 删除下标为index的元素
 * @param index
 * @return
 */
public Object remove(int index) {
    if(index < 0 || index >= size) {
        throw new ArrayIndexOutOfBoundsException(index);
    }
    Object o = get(index);
    for(int i = index;i<size;i++) {
        list[i] = list[i+1];
    }
    size--;
    return o;
}

 

查询数据与修改数据都比较简单,直接利用相应的下标进行替换或返回相应的值,判断链表为空直接判断size的值就可以了,而清空链表就将size的值修改为0

/**
 * 获取下标处的元素
 * 
 * @param index 下标
 * @return
 */
public Object get(int index) {
    if (index >= size || index < 0) {
        throw new ArrayIndexOutOfBoundsException(index);
    }
    return list[index];
}

/**
 * 判断列表是否为空
 * 
 * @return
 */
public boolean isEmpty() {
    return size == 0;
}

/**
 * 清空列表
 */
public void clear() {
    size = 0;
}

/**
 * 列表大小
 * 
 * @return
 */
public int size() {
    return size;
}

 都是比较粗糙的实现,暂时还未考虑优化

posted @ 2019-01-24 15:56  _chacha  阅读(445)  评论(0编辑  收藏  举报