我们对数组进行改造的原理如下:重新建立一个capacity更大的数组,通过for循环让原来数组的数据复制到新的数组里,再让我们原来的数组指向newdate
这样我们的date和newdate指向的同一个空间,我们会把这样一个过程封装在函数里,newdate会在执行完后被回收
package www.zxx;
public class Array<E> {
private E[] data;
private int size;
//带参构造函数
public Array(int capacity) {
//不支持new一个泛型数组
//先建立一个object类再进行强转
data = (E[])new Object[capacity];
size = 0;
}
//无参构造函数输入的数据实际上是capacity的值
public Array() {
this(10);
}
//获得数组的size
public int getSize() {
return size;
}
//获得数组的容量
public int getCapacity() {
return data.length;
}
//通过已经写好的add函数写一个在开头添加e值的函数
//好处是add函数已经处理过index数值的溢出问题
public void addFirst(E e) {
add(0, e);
}
//通过已经写好的add函数写一个在末尾添加e值的函数
//好处是add函数已经处理过index数值的溢出问题
public void addLast(E e) {
add(size, e);
}
//在index位置加入e数值的数
//要进行index数值的输入控制
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed,Index beyond brode");
}
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++;
}
//判断e数值在不在数组内
public boolean contains(E e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e))
return true;
}
return false;
}
//找数组中为e数值的位置,如果没有输出-1
public int find(E e) {
for (int i = 0; i < size; i++) {
//值比较
if (data[i].equals(e))
return i;
}
return -1;
}
@Override
//重写tostring方法让System.out.println()能直接输出我们指定的类型
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(',');
} else {
res.append(']');
}
}
return res.toString();
}
// 获得index位置的数
E get(int index) {
if (index < 0 || index >= size)
throw new IllegalArgumentException("Get failed.Index beyond brode.");
return data[index];
}
// 设置index位置的数为e
void set(int index, E e) {
if (index < 0 || index >= size)
throw new IllegalArgumentException("Get failed.Index beyond brode.");
data[index] = e;
}
//删除index位置的元素
//返回删除的元素
E remove(int index) {
if (index < 0 || index >= size)
throw new IllegalArgumentException("Get failed.Index beyond brode.");
E rec = data[index];
for(int i = index ; i < size ;i++) {
data[i] = data[i+1];
}
//我们的int类型的数组size指向的值不需要被删除,因为我们在后面插入的时候能覆盖
//在泛型中我们使用的是类对象,我们应该删除它
size--;
//loitering objects!=memory leak(内存泄漏)
data[size]=null;
return rec;
}
//删除第一个元素
public E removeFirst() {
return remove(0);
}
//删除最后一个元素
public E removeLast() {
return remove(size-1);
}
//从数组中寻找e数值的值,如果找到删除它
public void removeElement(E e) {
int index = find(e);
if(index != -1) {
remove(index);
}
}
//扩容
private void resize(int newCapacity) {
E[] newData = (E[])new Object[newCapacity];
for(int i = 0; i < size;i++) {
newData[i] = data[i];
}
data = newData;
}
//主方法
public static void main(String[] args) {
Array<Integer> arr = new Array<Integer>();
for (int i = 0; i < 10; i++) {
arr.addLast(i);
}
System.out.println(arr);
arr.add(1, 100);
System.out.println(arr);
arr.addFirst(-1);
System.out.println(arr);
arr.remove(0);
System.out.println(arr);
arr.removeElement(0);
System.out.println(arr);
}
}
在这里我们选择扩容的时候选择的是2*capacity
从结果中我们可以看到在我们add的时候超出了原来的capacity我们在add函数里进入到条件size==data.length进行了两倍扩容操作
上面的是扩容,相应的我们应该有减少容量
package www.zxx;
public class Array<E> {
private E[] data;
private int size;
//带参构造函数
public Array(int capacity) {
//不支持new一个泛型数组
//先建立一个object类再进行强转
data = (E[])new Object[capacity];
size = 0;
}
//无参构造函数输入的数据实际上是capacity的值
public Array() {
this(10);
}
//获得数组的size
public int getSize() {
return size;
}
//获得数组的容量
public int getCapacity() {
return data.length;
}
//通过已经写好的add函数写一个在开头添加e值的函数
//好处是add函数已经处理过index数值的溢出问题
public void addFirst(E e) {
add(0, e);
}
//通过已经写好的add函数写一个在末尾添加e值的函数
//好处是add函数已经处理过index数值的溢出问题
public void addLast(E e) {
add(size, e);
}
//在index位置加入e数值的数
//要进行index数值的输入控制
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed,Index beyond brode");
}
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++;
}
//判断e数值在不在数组内
public boolean contains(E e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e))
return true;
}
return false;
}
//找数组中为e数值的位置,如果没有输出-1
public int find(E e) {
for (int i = 0; i < size; i++) {
//值比较
if (data[i].equals(e))
return i;
}
return -1;
}
@Override
//重写tostring方法让System.out.println()能直接输出我们指定的类型
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(',');
} else {
res.append(']');
}
}
return res.toString();
}
// 获得index位置的数
E get(int index) {
if (index < 0 || index >= size)
throw new IllegalArgumentException("Get failed.Index beyond brode.");
return data[index];
}
// 设置index位置的数为e
void set(int index, E e) {
if (index < 0 || index >= size)
throw new IllegalArgumentException("Get failed.Index beyond brode.");
data[index] = e;
}
//删除index位置的元素
//返回删除的元素
E remove(int index) {
if (index < 0 || index >= size)
throw new IllegalArgumentException("Get failed.Index beyond brode.");
E rec = data[index];
for(int i = index+1 ; i < size ;i++) {
data[i-1] = data[i];
}
//我们的int类型的数组size指向的值不需要被删除,因为我们在后面插入的时候能覆盖
//在泛型中我们使用的是类对象,我们应该删除它
size--;
//loitering objects!=memory leak(内存泄漏)
data[size]=null;
if(size == data.length / 2)
resize(data.length/2);
return rec;
}
//删除第一个元素
public E removeFirst() {
return remove(0);
}
//删除最后一个元素
public E removeLast() {
return remove(size-1);
}
//从数组中寻找e数值的值,如果找到删除它
public void removeElement(E e) {
int index = find(e);
if(index != -1) {
remove(index);
}
}
//扩容
private void resize(int newCapacity) {
E[] newData = (E[])new Object[newCapacity];
for(int i = 0; i < size;i++) {
newData[i] = data[i];
}
data = newData;
}
//主方法
public static void main(String[] args) {
Array<Integer> arr = new Array<Integer>();
for (int i = 0; i < 10; i++) {
arr.addLast(i);
}
System.out.println(arr);
arr.add(1, 100);
System.out.println(arr);
arr.addFirst(-1);
System.out.println(arr);
arr.remove(0);
System.out.println(arr);
arr.removeElement(0);
System.out.println(arr);
arr.remove(0);
System.out.println(arr);
arr.removeFirst();
System.out.println(arr);
arr.removeFirst();
System.out.println(arr);
arr.removeFirst();
System.out.println(arr);
arr.removeFirst();
System.out.println(arr);
arr.removeFirst();
System.out.println(arr);
}
}
在把容量见效的时候还发现了一个隐形bug- -就是remove函数中的移动元素
之前的循环:
for(int i = index ; i < size ;i++) {
data[i] = data[i+1];
}
修改后的循环:
for(int i = index+1 ; i < size ;i++) {
data[i-1] = data[i];
}
我看了一下测试的数据- -因为之前在做remove操作的时候都没有超过容量,但其实i+1从index开始的话会到size
错误发生在第二次remove,这时我们的循环到了size出现了数组越界
要体会两种循环的差异