基本概念
所谓数组,是有序的元素序列。也就是把数据码成一排存放的一种结构。
最大的优点
快速查询,根据索引可以快速查找相应的元素
二次封装自己的数组(相当于Java中的ArrayList)
一个数组应该具备的功能(并不固定,还可以扩充一些功能)
- 获取数组的初始容量
- 获取数组中元素的个数
- 判断数组是否为空
- 添加元素
- 删除元素
- 修改元素
- 查找元素
1 /** 2 * 动态数组 3 * @param <E> 4 */ 5 public class MyArray<E> { 6 /** 7 * 元素集合 8 */ 9 private E[] data; 10 11 /** 12 * 数组中元素个数 13 */ 14 private int size; 15 16 /** 17 * 数组当前容量 18 */ 19 private int capacity; 20 21 public MyArray(int capacity) { 22 data = (E[]) new Object[capacity]; 23 size = 0; 24 } 25 26 public MyArray() { 27 capacity = 10; 28 data = (E[]) new Object[capacity]; 29 size = 0; 30 } 31 32 public int getSize() { 33 return size; 34 } 35 36 public int getCapacity() { 37 return capacity; 38 } 39 40 /** 41 * 判断数组是否为空 42 */ 43 public boolean isEmpty() { 44 return size == 0; 45 } 46 47 /** 48 * 在指定位置添加元素--O(n) 49 * @param index -索引 50 * @param e -元素 51 */ 52 public void add(int index, E e) { 53 if (size == capacity) { 54 //扩容2倍大小 55 resize(2 * capacity); 56 } 57 if (index < 0 || index > size) { 58 throw new IllegalArgumentException("add fail, Required index >=0 && index <=size"); 59 } 60 for (int i = size - 1; i >= index; i--) { 61 data[i + 1] = data[i]; 62 } 63 data[index] = e; 64 size++; 65 } 66 67 /** 68 * 在数组尾部添加元素--O(1) 69 */ 70 public void addLast(E e) { 71 add(size, e); 72 } 73 74 /** 75 * 在数组首部添加元素--O(n) 76 */ 77 public void addFirst(E e) { 78 add(0, e); 79 } 80 81 /** 82 * 删除数组中index位置的元素并返回--O(n) 83 * @param index -索引 84 * @return 85 */ 86 public E remove(int index) { 87 if (index < 0 || index >= size) { 88 throw new IllegalArgumentException("remove fail, index is illegal"); 89 } 90 E ret = data[index]; 91 for (int i = index + 1; i < size; i++) { 92 data[i - 1] = data[i]; 93 } 94 size--; 95 //使用泛型后 数组中size位置存放的是类对象的引用 手动释放空间 96 data[size] = null; 97 //防止复杂度震荡--以及数组长度为1的情况 98 if (size == capacity / 4 && capacity / 2 != 0) { 99 //缩容 100 resize(capacity / 2); 101 } 102 return ret; 103 } 104 105 /** 106 * 删除数组中第一个元素--O(n) 107 */ 108 public E removeFirst() { 109 return remove(0); 110 } 111 112 /** 113 * 删除数组中最后一个元素--O(n) 114 */ 115 public E removeLast() { 116 return remove(size - 1); 117 } 118 119 /** 120 * 设置数组某个位置的元素 121 * @param index -索引 122 * @param e -元素 123 */ 124 public void set(int index, E e) { 125 if (index < 0 || index >= size) 126 throw new IllegalArgumentException("set fail, index is illegal"); 127 data[index] = e; 128 } 129 130 /** 131 * 查询数组某个索引的元素 132 * @param index -索引 133 * @return E 134 */ 135 public E get(int index) { 136 if (index < 0 || index > size) { 137 throw new IllegalArgumentException("get fail, index is illegal"); 138 } 139 return data[index]; 140 } 141 142 /** 143 * 查询数组中是否存在元素 144 */ 145 public boolean contains(E e) { 146 for (int i = 0; i < size; i++) { 147 if (data[i] == e) 148 return true; 149 } 150 return false; 151 } 152 153 /** 154 * 数组长度动态变化 155 * @param newCapacity --新的容量 156 */ 157 private void resize(int newCapacity) { 158 E[] newData = (E[]) new Object[newCapacity]; 159 for (int i = 0; i < size; i++) { 160 newData[i] = data[i]; 161 } 162 data = newData; 163 capacity = newCapacity; 164 } 165 166 @Override 167 public String toString() { 168 StringBuilder res = new StringBuilder(); 169 res.append(String.format("Array: size = %d , capacity = %d\n", size, capacity)); 170 res.append('['); 171 for (int i = 0; i < size; i++) { 172 res.append(data[i]); 173 if (i != size - 1) { 174 res.append(','); 175 } 176 } 177 res.append(']'); 178 return res.toString(); 179 } 180 }
复杂度分析
什么是时间复杂度这里看另外一篇文章https://blog.csdn.net/qq_41523096/article/details/82142747
- 添加元素---O(n)-------复杂度分析一般考虑最坏的情况
- 在数组首部添加元素---O(n)---因为向数组头添加元素 需要把每个元素向后挪
- 在数组尾部添加元素)---O(1)
- 在数组指定位置添加元素---O(n/2)=O(n)---平均的情况下添加元素每次需要挪n/2个元素
- 扩容resize()---O(n)--最坏情况
- 删除元素---O(n)
- 删除数组首部元素---O(n)---因为向数组头添加元素 需要把每个元素向前挪
- 删除数组尾部元素---O(1)
- 删除数组指定位置元素---O(n/2)=O(n)
- 缩容resize()---O(n)--最坏情况
- 修改元素---set(index,e)---已知索引是O(1)---未知索引是O(n)--因为需要遍历数组中每一个元素
- 查找元素---已知索引是O(1)---未知索引是O(n)--因为需要遍历数组中每一个元素
- 根据索引查找元素--O(1)
- 判断元素是否存在---O(n)---因为需要遍历数组中每一个元素
- 查找元素对应的索引---O(n)
- 容量动态变化resize()--不应该考虑最坏情况,这是不合理的,因为不可能每次都触发这个方法--均摊复杂度
假设数组容量是8,使用addLast()方法需要9次操作才触发一次resize(转移8个元素到新数组),一共17次操作,相当于平均每次addLast,进行2次操作,所以均摊计算它的复杂度是O(1);
同理removeLast也是O(1); 同时考虑这两个方法,特殊情况当添加一个元素触发了扩容,然后有删除这个元素触发缩容,造成复杂度震荡.解决方法Lazy 也就是缩容的时候不用那么急