【数据结构】手动实现基础数据结构_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; }
都是比较粗糙的实现,暂时还未考虑优化