封装属于自己的数组
封装一个属于自己的数组,可以进行增删改查等操作,还可以不同的数据类型,以自己的格式输出。
下面是数组里的方法一览
add方法
想要在指定位置添加一个元素,那么这个位置后面的元素必须全部向后移一位,我们可以从最后一个元素开始遍历,每个元素向后移一位,移完后则指定位置空余出来,再将元素添加进去,在此之前,我们还要判断元素是否已经填满数组,还要输入的指定值是否小于0或者大于元素个数,完成这个方法后,我们可以在首尾添加元素时将此方法复用
public void add(int index,E e){
if (size==data.length){
throw new IllegalArgumentException("Array add is failed");
}
if (index<0 ||index>size){
throw new IllegalArgumentException("Array add id failed");
}
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);
}
查
在此之前,我们可以重写toString方法,以自己的格式输出结果,
@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<data.length;i++){
res.append(data[i]);
if (i!=size-1){
res.append(",");
}
}
res.append("]");
return res.toString();
}
根据索引位置获取元素和更改元素
public E get(int index){
return data[index];
}
public void set(int index,E e){
data[index]=e;
}
remove方法
同理,删除一个元素也要判断输入索引位置是否小于0或者大于大于元素个数,这里删除则是从index位置开始,后面元素覆盖当前元素值,并返回一个索引值
public E remove(int index){
if (index<0 ||index>=size){
throw new IllegalArgumentException("Array remove is failed");
}
E ret=data[index];
for (int i=index+1;i<size;i++){
data[i-1]=data[i];
}
size--;
data[size]=null;
return ret;
}
这里也可以复用remove方法,并且用于removeFirst和removeLast
public E removeLast(){
return remove(size);
}
public E removeElement(E e){
int index=find(e);
return remove(index);
}
动态数组
这里我们可以自己设计一个动态数组,用一个resize方法,而扩容的容量选择为原来数组的两倍,ArrayList选择的是1.5倍,这个resize方法,是将原来数组的内容复制到新的扩容数组里面,以此替代原来数组,达到扩容目的
/*
动态数组,扩容,将原来的数组内容复制到一个已扩容的数组里面,再指向该数组,即完成数组扩容
resize方法虽然复杂度较大,但是均摊复杂度后,依然不失为一种提高性能的方法
*/
public void resize(int newcapacity){
E[] newData=(E[])new Object[newcapacity];
for (int i=0;i<size;i++){
newData[i]=data[i];
}
data=newData;
}
数组既然可以扩容,我们也可以缩小容量,可以在remove方法里调用,做个判断,当数组元素个数变为数组容量的1/4时,我们调用resize方法,我们不选择在1/2数组容量时调用是因为有个复杂度振荡问题,比如原来数组容量为10,我们在后面加一个元素后数组容量扩容为20,此时时间复杂度又耗费O(n),当我们又删除一个元素时,如果是1/2容量时缩小,则又耗费O(n)时间复杂度,所以循环以往,就会造成复杂度振荡
源代码
public class Array <E>{
private E [] data;
private int size;//元素个数
//带参构造函数,初始化数组容量为capacity
public Array(int capacity){
data=(E[])new Object[capacity];
size=0;
}
//无参构造函数
public Array(){
this(10);
}
//获取数组中元素个数
public int getSize(){
return size;
}
//获取数组容量大小
public int getCapacity(){
return data.length;
}
//判断数组是否为空
public boolean isEmpty(){
return size==0;
}
/*
往数组指定位置添加元素
*/
public void add(int index,E e){
if (size==data.length){
resize(2*data.length);
}
if (index<0 ||index>size){
throw new IllegalArgumentException("Array add id failed");
}
for (int i=size-1;i>=index;i--){
data[i+1]=data[i];
}
data[index]=e;
size++;
}
/*
动态数组,扩容,将原来的数组内容复制到一个已扩容的数组里面,再指向该数组,即完成数组扩容
resize方法虽然复杂度较大,但是均摊复杂度后,依然不失为一种提高性能的方法
*/
public void resize(int newcapacity){
E[] newData=(E[])new Object[newcapacity];
for (int i=0;i<size;i++){
newData[i]=data[i];
}
data=newData;
}
public void addLast(E e){
add(size,e);
}
public void addFirst(E e){
add(0,e);
}
/*
构造自己的输出格式
*/
@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<data.length;i++){
res.append(data[i]);
if (i!=size-1){
res.append(",");
}
}
res.append("]");
return res.toString();
}
public E get(int index){
return data[index];
}
public void set(int index,E e){
data[index]=e;
}
/*
以下是包含,搜索和删除
*/
public boolean contains(E e){
for(int i=0;i<data.length;i++){
if (data[i].equals(e)) {
return true;
}
}
return false;
}
//找出搜索元素的索引
public int find(E e){
for(int i=0;i<data.length;i++){
if (data[i].equals(e)) {
return i;
}
}
return -1;
}
//删除指定位置元素
public E remove(int index){
if (index<0 ||index>=size){
throw new IllegalArgumentException("Array remove is failed");
}
E ret=data[index];
for (int i=index+1;i<size;i++){
data[i-1]=data[i];
}
size--;
data[size]=null;
//数组缩小,这里缩小到1/4是为了防止复杂度振荡
if (size==data.length/4&& data.length / 2 != 0){
resize(data.length/4);
}
return ret;
}
public E removeLast(){
return remove(size);
}
public E removeElement(E e){
int index=find(e);
return remove(index);
}
public void removeAllElement(E e){
for(int i=0;i<size;i++){
if (data[i]==e) {
remove(i);
}
}
}
/*
使用泛型,可以让数组承载任意类型,包括用户自定义的类,但只能是类对象,像基本数据类型不可以
得用它们的包装类,如Boolean,Byte,Char,Short,Long,String,Integer,Double
*/
}