前言
模拟Java中的ArrayList数据结构
自定义长度可变数组
写了三个版本:
1.存放字符串
2.使用泛型
3.优化的自定义长度可变数组
一、用来存放字符串
对数据的操作:放数据,取数据,删除数据,修改数据,获得数据个数
public class DynamicArray {
//先定义一个初始长度为0的数组,用来存储数据
private String[] src=new String[0];
//插入元素
public void add(String s) {
//先定义一个新数组,长度是src.length+1
String[] dest=new String[src.length+1];
//数组拷贝
System.arraycopy(src, 0, dest, 0, src.length);
//将src指向新数组,src原来指向的内存由于没有变量指向它会被java当中的GC自动回收
//src的长度改变了
src=dest;
//将新数据放到数组最后一个位置
src[src.length-1]=s;
}
//指定位置插入
public void add(int index,String s) {
String[]dest=new String[src.length+1];
System.arraycopy(src, 0, dest, 0, index);
System.arraycopy(src, index, dest, index+1, src.length-index);
src=dest;
src[index]=s;
}
//删除指定位置
public void delete(int index){
String[]dest=new String[src.length-1];
System.arraycopy(src, 0, dest, 0, index);
System.arraycopy(src, index+1, dest, index,src.length-index-1);
src=dest;
}
//删除指定内容
public void delete(String s) {
String[]dest=new String[src.length-1];
for(int i=0;i<src.length;i++) {
if(src[i].equals(s)) {
delete(i);
break;//只删掉一个s
}
}
}
//修改指定位置
public void update(int index,String s) {
src[index]=s;
}
public String get(int index) {
return src[index];
}
public int size() {
return src.length;
}
}
二、使用泛型
泛型:在定义的时候不明确变量的具体类型,而是等到使用的时候再明确
泛型类的定义:在定义类的时候声明一个泛型,在这个类中就可以使用这个泛型作为一种数据类型
通常情况下,泛型变量名都采用大写字母来表示
public class DynamicArray2<E> {
//先定义一个初始长度为0的数组,用来存储数据
//初始状态下,还没有数据,长度为0
private Object[] src=new Object[0];
public void add(E s) {
//先定义一个新数组,长度是src.length+1
Object[] dest=new Object[src.length+1];
//数组拷贝
System.arraycopy(src, 0, dest, 0, src.length);
//将src指向新数组,src原来指向的内存由于没有变量指向它会被java当中的垃圾回收期GC自动回收
//src的长度改变了
src=dest;
//将新数据放到数组最后一个位置
src[src.length-1]=s;
}
//指定位置插入
public void add(int index,E s) {
Object[]dest=new Object[src.length+1];
System.arraycopy(src, 0, dest, 0, index);
System.arraycopy(src, index, dest, index+1, src.length-index);
src=dest;
src[index]=s;
}
//删除指定位置
public void delete(int index) {
Object[]dest=new Object[src.length-1];
System.arraycopy(src, 0, dest, 0, index);
System.arraycopy(src, index+1, dest, index,src.length-index-1);
src=dest;
}
//删除指定内容
public void delete(E s) {
Object[]dest=new Object[src.length-1];
for(int i=0;i<src.length;i++) {
if(src[i].equals(s)) {
delete(i);
break;//只删掉一个s
}
}
}
//修改指定位置
public void update(int index,E s) {
src[index]=s;
}
public E get(int index) {
return (E)src[index];
}
public int size() {
return src.length;
}
}
耗费时间的问题:
1.每增加一个数据,都需要新开辟数组的内存,开辟内存需要等待时间
2.每增加一个数据,都需要将原数组中的数据拷贝到新数组中,数据的迁移需要时间
三、优化的自定义长度可变数组
要想提高性能:
1.减少创建数组的次数
2.减少数组拷贝的次数
public class DynamicArray3<E> {
//数组的初始容量
private int init_capacity=3;
//先定义一个数组,用来存储数据
//初始状态下,使用初始容量作为数组长度
//当前实际容量就是数组的实际长度
private Object[] src=null;
//数组中的数据个数,默认是0个,数据的个数称之为长度可变数组的长度
private int count=0;
//重写默认的构造方法
public DynamicArray3() {
src=new Object[init_capacity];
}
//定义构造方法,在构造方法中传入初始容量,再创建数组,运行用户根据实际情况来确定数组的初始容量
public DynamicArray3(int capacity) {
init_capacity=capacity;
//根据传入的初始容量来创建初始数组
src=new Object[init_capacity];
}
public void add(E s) {
//先检查数据的个数是否达到容量上限
//如果达到上限,就需要创建新数组,对数字进行扩容
if(count==src.length) {
//创建新数组
Object[] dest=new Object[src.length+src.length/2];
//将原数组中的数组拷贝到新数组中
System.arraycopy(src, 0, dest, 0, src.length);
src=dest;
}
//如果没有达到上限,就将数据直接放到数组第一个为null的位置
//第一个为null的位置的下标就是count
src[count]=s;
count++;
}
/**
* 插入
* @param index
* @param s
*/
public void add(int index,E s) {
if(count==src.length) {
Object[] dest=new Object[src.length+src.length/2];
System.arraycopy(src, 0, dest, 0, index);
System.arraycopy(src, index, dest, index+1, src.length-index);
src=dest;
src[index]=s;
count++;
}else {
for(int i=count-1;i>=index;i--) {
src[i+1]=src[i];
}
src[index]=s;
count++;
}
}
/**
* 删除
* @param index
*/
public void delete(int index) {
if(index<0 || index>=count) {
//将错误信息封装成一个异常对象
IndexOutOfBoundsException ex=new IndexOutOfBoundsException("索引超出边界!");
//抛出异常对象,抛给调用此方法的对象,最终会抛给JVM
throw ex;
}else {
for(int i=index+1;i<count;i++) {
src[i-1]=src[i];
}
count--;
}
}
/**
* 删除
* @param s
*/
public void delete(E s) {
for(int i=0;i<count;i++) {
if(src[i].equals(s)) {
delete(i);
break;//只删掉一个s
}
}
}
/**
* 修改
* @param index
* @param s
*/
public void update(int index,E s) {
if(index<0 || index>=count) {
//将错误信息封装成一个异常对象
IndexOutOfBoundsException ex=new IndexOutOfBoundsException("索引超出边界!");
//抛出异常对象,抛给调用此方法的对象,最终会抛给JVM
throw ex;
}else {
src[index]=s;
}
}
/**
* 获取
* @param index
* @return
*/
public E get(int index) {
//判断索引的范围,如果超过范围,就抛出异常并介绍程序
if(index<0 || index>=count) {
//将错误信息封装成一个异常对象
IndexOutOfBoundsException ex=new IndexOutOfBoundsException("索引超出边界!");
//抛出异常对象,抛给调用此方法的对象,最终会抛给JVM
throw ex;
}
Object obj=src[index];
return (E)obj;
}
/**
* 数组大小
* @return
*/
public int size() {
//变量count就是数据的个数
return count;
}
}