数组(ArrayList)
普通数组
- 将数据码成一排进行存放
- 优点:通过下标来访问数组中的每一个元素(数组具有随机访问的能力)
- 缺点:数据容量一旦确定就不能更改(数据容量大小固定,是一种静态数据结构)
基于普通数组实现ArrayList
ArrayList
的基本功能
ArrayList
的基本功能不外乎增、删、改、查等操作- 从零开始实现
Array
我们可以仿造ArrayList
的基本功能,通过以下的步骤逐步完成自己的Array
类 。-
首先——确定
Array
类的数据成员:
实现Array
类基于基本的数组,所以要有一个基本数组作为该类的属性值,同时要有一个capacity(容量)来表示当前Array
对象的容量,还应该要有一个size来表示当前Array
对象实际含有的元素个数。事实上,capacity可以通过基本数组的length属性来获得,因此只需要两个属性(基本数组 以及 size),代码如下:/** * 基于普通数组实现Array类 * @author wbkearly * @param <E> Array中元素类型 */ public class Array<E> { private E[] data; private int size; }
-
为
Array
类书写一些简单的方法/** * 构造函数,传入数组容量capacity构造Array * @param capacity 数组容量 */ public Array(int capacity) { data = (E[])new Object[capacity]; size = 0; } /** * 无参构造函数,默认容量capacity=10 */ public Array() { this(10); } /** * 获取数组中元素个数 * @return 数组中元素个数 */ public int getSize() { return size; } /** * 获取数组的容量 * @return 数组的容量 */ public int getCapacity() { return data.length; } /** * 判断数组是否为空 * @return 数组是否为空 */ public boolean isEmpty() { return size == 0; }
-
向
Array
中添加元素
值得注意的是,这里向Array
中添加元素和普通数组中添加元素有区别,在普通的数组中,当元素超过了容量时,会导致溢出,但是我们的Array
类具有自适应的能力,即它可以resize
,当数组元素个数大于容量时,它可以增大数组的容量,同时当数组元素个数小于一定范围时,它可以缩小数组的容量以减小程序内存的开销。// resize以调整Array大小 private void resize(int newCapacity) { E[] newData = (E[])new Object[newCapacity]; for(int i = 0; i < size; i++) { newData[i] = data[i]; } data = newData; } /** * 向数组第index位置插入一个新的元素e * @param index 要插入新的元素的位置 * @param e 要插入的新元素 */ public void add(int index, E e) { if(index < 0 || index > size) { throw new IllegalArgumentException("index越界,index范围需为[0,size]"); } if(size == data.length) { resize(2 * data.length); } for(int i = size - 1; i >= index; i--) { data[i + 1] = data[i]; } data[index] = e; size++; } // 基于add实现addFirst和addLast /** * 向所有元素前添加元素e * @param e 要添加的元素 */ public void addFirst(E e) { add(0, e); } /** * 向所有元素后添加元素e * @param e 要添加的元素 */ public void addLast(E e) { add(size, e); }
-
从
Array
删除元素
分为两种,即删除指定下标位置元素和删除指定元素,代码如下:/** * 从数组中删除index位置的元素,并返回删除的元素 * @param index 要删除元素的索引index * @return 删除的元素 */ public E remove(int index) { if(index < 0 || index > size) { throw new IllegalArgumentException("remove失败!index越界,index范围需为[0,size]"); } E ret = data[index]; for(int i = index + 1; i < size; i++) { data[i-1] = data[i]; } size--; data[size] = null; if(size == data.length / 4 && data.length / 2 != 0) { resize(data.length / 2); } return ret; } // 基于remove实现removeFirst和removeLast /** * 从数组中删除第一个元素 * @return 原数组中的第一个元素 */ public E removeFirst() { return remove(0); } /** * 从数组中删除最后一个元素 * @return 原数组中的最后一个元素 */ public E removeLast() { return remove(size - 1); } /** * 删除数组中值为e的元素 * @param e 待删除的元素e */ public void removeElement(E e) { int index = find(e); if(index != -1) { remove(index); } }
-
修改指定位置元素
/** * 修改index索引位置元素为e * @param index 要修改元素的索引 * @param e 修改index索引元素为e */ public void set(int index, E e) { if(index < 0 || index > size) { throw new IllegalArgumentException("set失败!index越界,index范围需为[0,size]"); } data[index] = e; }
-
查询元素
包括以下方法:/** * 获取第一个元素 * @return 数组第一个元素 */ public E getFirst() { return get(0); } /** * 获取数组最后一个元素 * @return 数组最后一个元素 */ public E getLast() { return get(size - 1); } /** * 修改index索引位置元素为e * @param index 要修改元素的索引 * @param e 修改index索引元素为e */ public void set(int index, E e) { if(index < 0 || index > size) { throw new IllegalArgumentException("set失败!index越界,index范围需为[0,size]"); } data[index] = e; } /** * 查找数组中是否包含元素e * @param e 要判断是否包含的元素e * @return 是否存在元素e */ public boolean contains(E e) { for(int i = 0; i < size; i++) { if(data[i].equals(e)) { return true; } } return false; } /** * 查找数组中元素e的索引,若不存在返回-1 * @param e 要查找索引的元素e * @return 元素e的索引,若不存在,则返回-1 */ public int find(E e) { for(int i = 0; i < size; i++) { if(data[i].equals(e)) { return i; } } return -1; }
-
Array
类的完整代码/** * 基于普通数组实现Array类 * @author wbkearly * @param <E> Array中元素类型 */ public class Array<E> { private E[] data; private int size; /** * 构造函数,传入数组容量capacity构造Array * @param capacity 数组容量 */ @SuppressWarnings("unchecked") public Array(int capacity) { data = (E[])new Object[capacity]; size = 0; } /** * 无参构造函数,默认容量capacity=10 */ public Array() { this(10); } /** * 获取数组中元素个数 * @return 数组中元素个数 */ public int getSize() { return size; } /** * 获取数组的容量 * @return 数组的容量 */ public int getCapacity() { return data.length; } /** * 判断数组是否为空 * @return 数组是否为空 */ public boolean isEmpty() { return size == 0; } /** * 向数组第index位置插入一个新的元素e * @param index 要插入新的元素的位置 * @param e 要插入的新元素 */ public void add(int index, E e) { if(index < 0 || index > size) { throw new IllegalArgumentException("index越界,index范围需为[0,size]"); } if(size == data.length) { resize(2 * data.length); } for(int i = size - 1; i >= index; i--) { data[i + 1] = data[i]; } data[index] = e; size++; } private void resize(int newCapacity) { @SuppressWarnings("unchecked") E[] newData = (E[])new Object[newCapacity]; for(int i = 0; i < size; i++) { newData[i] = data[i]; } data = newData; } /** * 向所有元素前添加元素e * @param e 要添加的元素 */ public void addFirst(E e) { add(0, e); } /** * 向所有元素后添加元素e * @param e 要添加的元素 */ public void addLast(E e) { add(size, e); } /** * 获取index索引位置的元素 * @param index 要获取的元素的索引 * @return index索引位置的元素 */ public E get(int index) { if(index < 0 || index > size) { throw new IllegalArgumentException("get失败!index越界,index范围需为[0,size]"); } return data[index]; } /** * 获取第一个元素 * @return 数组第一个元素 */ public E getFirst() { return get(0); } /** * 获取数组最后一个元素 * @return 数组最后一个元素 */ public E getLast() { return get(size - 1); } /** * 修改index索引位置元素为e * @param index 要修改元素的索引 * @param e 修改index索引元素为e */ public void set(int index, E e) { if(index < 0 || index > size) { throw new IllegalArgumentException("set失败!index越界,index范围需为[0,size]"); } data[index] = e; } /** * 查找数组中是否包含元素e * @param e 要判断是否包含的元素e * @return 是否存在元素e */ public boolean contains(E e) { for(int i = 0; i < size; i++) { if(data[i].equals(e)) { return true; } } return false; } /** * 查找数组中元素e的索引,若不存在返回-1 * @param e 要查找索引的元素e * @return 元素e的索引,若不存在,则返回-1 */ public int find(E e) { for(int i = 0; i < size; i++) { if(data[i].equals(e)) { return i; } } return -1; } /** * 从数组中删除index位置的元素,并返回删除的元素 * @param index 要删除元素的索引index * @return 删除的元素 */ public E remove(int index) { if(index < 0 || index > size) { throw new IllegalArgumentException("remove失败!index越界,index范围需为[0,size]"); } E ret = data[index]; for(int i = index + 1; i < size; i++) { data[i-1] = data[i]; } size--; data[size] = null; if(size == data.length / 4 && data.length / 2 != 0) { resize(data.length / 2); } return ret; } /** * 从数组中删除第一个元素 * @return 原数组中的第一个元素 */ public E removeFirst() { return remove(0); } /** * 从数组中删除最后一个元素 * @return 原数组中的最后一个元素 */ public E removeLast() { return remove(size - 1); } /** * 删除数组中值为e的元素 * @param e 待删除的元素e */ public void removeElement(E e) { int index = find(e); if(index != -1) { remove(index); } } /** * 重写Object类的toString方法 */ @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(String.format("Array: size = %d, capacity = %d\n", size, data.length)); stringBuilder.append("["); for(int i = 0; i < size; i++) { stringBuilder.append(data[i]); if(i != size - 1) { stringBuilder.append(", "); } } stringBuilder.append("]"); return stringBuilder.toString(); } }
总结:实现自己的Array类有助于加深我们对ArrayList的理解。