1.首先用Java手写一个动态扩容的数组。
package com.struct.array; public class Array<E> { /** * 存放数据的数组 */ private E[] data; /** * 数组中现有数据量 */ private int size; public Array(int capacity) { data = (E[])new Object[capacity]; size = 0; } /** * 默认数组长度10 */ public Array() { new Array<>(10); } /** * 得到数组长度 */ public int getCapacity() { return data.length; } /** * 已有数组大小 */ public int getSize() { return size; } /** * 判断数组是否为空 */ public boolean isEmpty() { return size == 0; } /** * 索引index处添加一个元素 * 1.判断索引是否有效 * 2.判断数组是否已经满了,若满了那么扩容 * 3.从后往前,index处的元素后移一个位置 * 4.index索引处元素赋值 * 5.size++ */ public void add(int index, E e) { if(index < 0 || index > size) { throw new IllegalArgumentException("add failed, index must between 0 and size"); } if(index == size) { resize( 2 * data.length); } for (int i = size -1; i >= index; i--) { data[i+1] = data[i]; } data[index] = e; size++; } /** * 在尾部添加新元素 */ public void addLast(E e) { add(size, e); } /** * 在头部添加新元素 */ public void addFirst(E e) { add(0, e); } /** * 是否包含否个元素 */ public boolean contains(E e) { for (E e1 : data) { if(e1.equals(e)) { return true; } } return false; } /** * 动态扩容 * 1.新建一个容器,大小为指定大小newCapacity * 2.将之前的容器的元素按原有顺序放到新的容器中 * 3.将原指针指向新容器 */ private void resize(int newCapacity) { E[] newDate = (E[]) new Object[newCapacity]; for(int i = 0; i < size; i++) { newDate[i] = data[i]; } data = newDate; } /** * 查找元素E在数组中的索引 * 1.遍历所有的数组,若匹配到(equals非==)那么返回索引,否则返回-1 */ private int find(E e) { for (int i = 0; i < data.length; i++) { if(data[i].equals(e)) { return i; } } return -1; } /** * 删除元素并返回删除之前的位置 * 若不存在则返回-1 */ public int removeElement(E e) { int index = find(e); if(index != -1) { remove(index); } return index; } /** * 根据索引删除元素,并返回删除元素 * 1.判断索引是否有效 * 2.将索引处的元素保存到单独一个变量,用于返回 * 3.将所有元素左移,索引从小到大 * 4.将size索引处的元素清空,并且size-1 * 5.均摊算法复杂度。为防止算法复杂度振荡,只有size <= data.leng/4 那么重新调整数组大小为原大小二分之一 * 注意数组容器大小不能为0 */ private E remove(int index) { if(index < 0 || index >= size) { throw new IllegalArgumentException("index must between 0 and size -1"); } E removeData = data[index]; for(int i = index + 1; i < size; i++) { data[i-1] = data[i]; } data[index] = null; size--; if(size <= data.length/4 && data.length /2 != 0) { resize(data.length /2); } return removeData; } }
2.算法负责度分析
添加操作O(n);
addLast O(1) addFirst O(n) add(index,e) O(n/2)即O(n)
均摊复杂度 amortized time complexity
假设capacity = n, n+1次addLast,出发resize, 总共进行2n+1次基本操作。那么平摊到每一次addLast,就是说每一次addLast进行2次基本操作。那么均摊复杂度O(1)。