今天来实现一个Java写的动态数组,就像平时使用的ArrayList一样,当容量不够时可以动态扩容,容量过大时可以动态缩容。
需要的一些方法:
有参构造Array(int capacity)
capacity用来指定数组大小
无参构造Array()
默认开辟10个对象大小的数组
getSize()
getCapacity()
isEmpty()
判断是否为空
find(E e)
查找函数
add(int index,E e)
向指定位置添加元素的方法
addFirst(E e)
向数组头部添加元素
addLast(E e)
向数组尾部添加元素
private resize(int capacity)
重新分配数组容量的方法
remove(int index)
删除指定位置的元素
removeFirst()
删除数组的第一个元素
removeLast()
删除数组的最后一个元素
get(int index)
获取指定位置的元素
contains(E e)
判断数组中是否存在元素e
set(int index,E e)
修改指定位置的元素
toString()
package com.yunding.dataStructures;
import java.util.Map;
/**
* @Author: Lang
* @Date: 2020/7/4
* @Description: 动态数组
*/
public class Array<E> {
private E[] data;
private int size;
//构造函数,传入数组的容量capacity构造Array
public Array(int capacity){
data = (E[])new Object [capacity];
size = 0;
}
//无参构造,默认数组容量为10
public Array(){
this(10);
}
//获取数组中的元素个数
public int getSize(){
return size;
}
//获取数组的容量
public int getCapacity(){
return this.data.length;
}
//返回数组是否为空
public boolean isEmpty(){
return size == 0;
}
//向所有的元素后添加一个新元素
public void addLast(E e){
add(size,e);
}
//向数组首地址添加一个新元素
public void addFirst(E e){
add(0,e);
}
//添加元素
public void add(int index,E e){
if(index < 0 || index > size){
throw new IllegalArgumentException("index<0 or index>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 capacity) {
E[] newData = (E[]) new Object[capacity];
for(int i=0;i<size;i++){
newData[i] = data[i];
}
data = newData;
}
//从数组中删除index位置的元素,返回删除的元素
public E remove(int index){
if(index < 0 || index > size){
throw new IllegalArgumentException("index<0 or index>size");
}
E ret = data[index];
for(int i = index+1 ; i < size ; i++){
data[i-1] = data[i];
}
size--;
//动态缩容
if(size == data.length/4 && data.length/2 != 0){
resize(data.length/2);
}
return ret;
}
//删除数组第一个元素
public E removeFirst(){
return remove(0);
}
//删除数组最后一个元素
public E removeLast(){
return remove(size-1);
}
//查找指定位置的元素
public E get(int index){
return data[index];
}
//查询是否包含
public boolean contains(E e){
for(int i=0;i<size;i++){
if(data[i].equals(e)){
return true;
}
}
return false;
}
//修改指定下标的元素,并返回修改前的元素
public E set(int index,E e){
if(index < 0 || index > size){
throw new IllegalArgumentException("index<0 or index>size");
}
E e1 = data[index];
data[index] = e;
return e1;
}
//查找元素并返回元素的下标,如果不存在则返回-1
public int find(E e){
for(int i = 0; i < size; i++){
if(data[i].equals(e)){
return i;
}
}
return -1;
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append(String.format("Array: size = %d , capacity = %d \n",size,data.length));
res.append('[');
for(int i = 0; i < size; i++){
res.append(data[i]);
if(i!=size-1){
res.append(",");
}
}
res.append(']');
return res.toString();
}
}
核心在于add(),remove()和resize()
方法,添加方法会在容量不足时重新申请内存扩容,容量达到原来的两倍。
而删除元素当现有元素是数组容量的1/2时并不会立马缩容,因为为防止复杂度震荡,复杂度震荡是什么呢?
当一个数组原有容量为n,当数组满后继续添加元素就会扩容,当再删除一个元素,又进行缩容,再添加元素时又进行扩容,这样就会导致复杂度很高。
所以,为了防止这种情况,删除元素时可以在数组的元素为数组长度的1/4时再进行缩容,这样可以有效避免复杂度震荡。
操作 | first | last | 一般 |
---|---|---|---|
添加元素 | O(n) | O(1) | O(n/2)=O(n) |
删除元素 | O(n) | O(1) | O(n/2)=O(n) |
修改元素 | set(int index,E e) | O(1) |
查找元素 | get(int index) | contains(E e) | find(E e) |
---|---|---|---|
O(1) | O(n) | O(n) |