1 前言
利用java语言,仿照ArrayList实现自己的动态数组,以加深对动态数组的理解
2 动态数组 Array实现
/**
* @author Created by qiyei2015 on 2018/4/27.
* @version: 1.0
* @email: 1273482124@qq.com
* @description: 动态数组
*/
public class Array<E> {
/**
* 默认容量大小
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 保存元素的数组
*/
private E[] element;
/**
* 元素个数大小
*/
private int size;
/**
* 容量大小
*/
private int capacity;
/**
* 默认构造函数
*/
public Array() {
this(DEFAULT_CAPACITY);
}
/**
* 构造方法
* @param capacity
*/
public Array(int capacity){
this.capacity = capacity;
size = 0;
element = (E[])new Object[capacity];
}
/**
* 添加元素
* @param t
*/
public void addFirst(E t){
add(0,t);
}
/**
* 添加元素
* @param t
*/
public void addLast(E t){
add(size,t);
}
/**
*
* @param index
* @param t
*/
public void add(int index,E t){
if (index < 0 || index > size){
throw new IllegalArgumentException("index illegal");
}
if (size == capacity){
resize(2 * capacity);
}
//右移一位
for (int i = size - 1; i >= index ;i--){
element[i+1] = element[i];
}
element[index] = t;
size++;
}
/**
* 删除第0个
* @return
*/
public E removeFirst(){
return remove(0);
}
/**
* 删除末尾元素
*/
public E removeLast(){
return remove(size - 1);
}
/**
* 删除元素
* @param index
*/
public E remove(int index){
if (index < 0 || index >= size){
throw new IllegalArgumentException("index illegal");
}
E e = element[index];
//左移一位
for (int i = index;i < size;i++){
element[i] = element[i + 1];
}
size--;
element[size] = null;
//缩容到一半,防止震荡
if ((size == capacity / 4) && ((capacity / 2) != 0)){
resize(capacity / 2);
}
return e;
}
public E getFirst(){
return get(0);
}
public E getLast(){
return get(size - 1);
}
/**
* 获取该元素
* @param index
* @return
*/
public E get(int index){
if (index < 0 || index >= size){
throw new IllegalArgumentException("index illegal");
}
return element[index];
}
/**
* 修改
* @param index
* @param e
*/
public void set(int index,E e){
if (index < 0 || index >= size){
throw new IllegalArgumentException("index illegal");
}
element[index] = e;
}
/**
* 判断是否为null
* @return
*/
public boolean isEmpty(){
return size == 0;
}
/**
* 返回大小
* @return
*/
public int size(){
return size;
}
/**
* 容量大小
* @return
*/
public int getCapacity(){
return capacity;
}
/**
* 调整数组大小
* @param n
*/
private void resize(int n) {
E[] newData = (E[]) new Object[n];
//拷贝元素
System.arraycopy(element,0,newData,0,size);
element = newData;
capacity = element.length;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(String.format("Array:size=%d,capacity=%d\n",size,capacity));
builder.append("[");
for (int i = 0 ; i < size ; i++){
builder.append(element[i]);
if (i != size - 1){
builder.append(",");
}
}
builder.append("]");
return builder.toString();
}
}
3 时间复杂度分析
1 添加
add(index,e) O(n)
addLast(e) O(1)
addFirst(e) O(n)
2 删除
remove(index) O(n)
removeLast() O(1)
removeFirst() O(n)
3 修改
set(index,e) O(1)
4 查询
get(index) O(1)
contains(e) O(n)
find(e) O(n)
4 均摊分析和复杂度震荡
1 resize均摊分析
n+1 次addlast操作,触发resize,总共进行了2n+1 次基本操作,因此每次addlast平均进行了2次基本操作
时间复杂度是o(1)
2 复杂度震荡
但是同时看addlast和removelast可能出现复杂度震荡,在临界点add了又remove,
出现原因 removelast时resize过于着急,
解决方案 lazy懒惰策略
缩容时判断当前占用是四分之一时才缩容,并且只缩容为1/2
另外可以参考ArrayList的缩容策略,每次删除后,移动数组后,将elementData[–size] = null; 这样数组长度也就减1了。