自定义数据结构之数组


前言

模拟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;
 }
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页