目录
数组的结构特点:
数组是内存的一块连续空间
数组可以通过下标进行访问操作数据
下标: 从0开始(将数组中的第一个位置的内存地址转为标号0),依次向后递增1
长度: 整个数组中可以存储的元素个数
一维数组: 数组中存储的元素都是数据元素定义格式: 数组存储的数据类型[] 数组名= new 数据类型[存储的元素个数];
二维数组: 是一个一维数组中存储了多个一维数组
定义格式: 数组存储的数据类型[][] 数组名 = new 数据类型[存储的一维数组个数][每个
一维数组中存储的元素个数];
1、动态数组的概念
什么是动态数组?动态数组就是在普通数组上增加了一个可以根据元素的个数动态调整数组大小的功能。Java中提供的数组一般都是静态数组:例如(int[]char[]long[])这时候就需要我们自己定义一个类,拓展基础数组的功能就为动态数组。优势是可以灵活地添加或删除元素,而一般数组则受限于固定的内存空间,只能添加元素。数组也是一种线性结构,但是它在计算机存储的时候,往往都是直接在内存中声明的时候就定义好了自身容量的大小,这就造成了往往后面在使用的时候,容量不够,又需要重新开辟一个更大的数组,将原来的数组内容全部拷贝过去,浪费了大量的时间和资源。
public class Array {
private int[] data;
//存放元素仍是整型数组;
private int size;
//表是动态数组中已经存储的元素个数;
}
2、动态数组的变量和构造方法
首先需要设置一个内部数组用来存储输入的数组,然后设置一个size用来记录add方法中插入的位置。再设置一个默认变量,在无参构造中使用。创建两个构造方法,如果没有输入明确的数组长度,默认产生对象时,初始化长度为10。另一个构造方法则输入了数组长度,创建一个相应长度的数组。
public class MyArray<P>{
// 什么类型的数据都可以存的数组
Object[] values;
int size;// 作为元素个数 / 作为下次存储元素的下标
int length;
static final int initCap = 10;//设置初始长度
// 构造方法:
public MyArray(){
length = initCap;
values = new Object[length];
size = 0;
}
// 构造方法:
public MyArray(){
length = initCap;
values = new Object[length];
size = 0;
}
或者是这样
public class MyArray implements SeqList {
private int[] elementData;
private int size;
private static final int DEFAULT_CAPACITY = 10;
public MyArray() {
this(DEFAULT_CAPACITY);
}
public MyArray(int capacity){
this.elementData = new int[capacity];
}
}
3.添加元素
首先!!!!important!!
需要排除非法情况,就是数组长度为0时,需要抛出异常。size的位置恰好就是当前数组中尾部插入元素的位置,完全插入后size就可以记录当前线性表中的实际元素个数。下面给出动态数组的接口设计,你也可以理解为动态数组可以做什么
int size(); // 元素的数量
boolean isEmpty();// 是否为空
boolean contains(E element); // 是否包含采个元素
void add(E element);//添加元素到最后面
E get(int index); //返回index位置 对应的元素
E set(int index, E element); // 设置index位置的元素
void add(int index, E element);//往index位置添加元素
E remove(int index);//删除index位置对应的元素
int indexOf(E element);//查看元素的位置
void clear();//清除所有元素
下一步就是灵活使用循环语句实现动态的扩大数组的存储大小,示例子如下:
public class MyArray{
// 什么类型的数据都可以存的数组
Object[] values;
int size;// 作为元素个数 / 作为下次存储元素的下标
int length;
static final int initCap = 10;
// 构造方法:
public MyArray(){
length = initCap;
values = new Object[length];
size = 0;
}
public MyArray(int initLength){
if(initLength < 2){
System.out.println ("输入的初始长度不能小于2,数组会使用默认的初始数据进行初始
化");
length = initCap;
values = new Object[length];
size = 0;
} else{
length = initLength;// 使用传入的参数进行初始化
values = new Object[length];
size = 0;
}
}
public void add(Object e){
// 扩容
if(size == length){// 数组已经存满了 需要扩容的
int oldLength = length;
int newLength = oldLength + (oldLength >> 1);// 1.5倍
// System.out.println (newLength);
// 使用新的长度创建一个新的 容量更大的数组
Object[] newValues = new Object[newLength];
// 将原数组中的元素i移动到新数组中
for(int i = 0; i < oldLength; i++){
newValues[i] = values[i];
}
// 将新数组的对象变量名中存储的新数组的内存地址赋值给旧数组名
values = newValues;
// 更新最新的数组长度
length = newLength;
System.out.println ("数组扩容完成,长度是:" + length);
}
values[size] = e;
size++;
}
// 将一个数组存入动态数组中 重点考虑扩容
public void addAll(Object[] eArr){
}
// 根据传入的下标获取数组元素
public Object get(int index){
// 检查传入的下标是否在合法的区间内 (0~size-1)
if(index >= 0 && index < size){
Object e = values[index];
return e;
}
System.out.println ("传入的下标不在数组的范围内~");
return null;
}
此时,可以通过使用
重点:
其实数据结构的操作无非就是增删改查,动态数组中查和改的操作非常简单,需要理解增加和删除的方法,在增加和删除的方法中使用到了扩容和缩容,放到各自方法下面去讲:
增加的操作:
看着图会更容易理解:
当index =2, 表明我们需要在index = 2 这个位置添加一个元素,
但是此时 index = 2位置已经有其他元素占用了,所以我们需要将该元素移动到其他位置,然后再将我们添加的元素放入2这个位置;
如何移动?向前向后?
肯定向后!!!,向前移动就将前面的元素覆盖了!
@Override
public void clear() {
//如果我们存储的是基本类型,那么下面这个循环就不需要执行
//但是我们使用了泛型,那么有可能存储对象类型
//所以需要将每一个对象都清空
//因为动态数组每一个值都指向一块内存地址,
//如果不清空,就会浪费内存空间
for(int i=0;i<size;++i){
elements[i] = null;
}
size = 0; //修改元素个数
//如果你的动态数组容量大于默认容量
//我们可以考虑把它的容量缩小为默认容量,为了避免销毁内存
//当然你也可以不用
if(elements!=null && elements.length>DEFAULT_CAPACITY){
elements = (E[]) new Object[DEFAULT_CAPACITY];
}
}