ArrayList和顺序表
目录
线性表
顺序表
实现顺序表:
1,添加元素的时候我们要判断是否需要扩容
2,写异常
3,数组清空
ArrayList:
ArrayList的构造方法:
ArrayList的add方法:
ArrayList的subList
知识点补充:数据结构中常见的接口关系图
ArrayList的打印
二维数组:
线性表
就是n个相同类型的数据有序排列;常见的有:顺序表,链表。栈,队列等
顺序表
实现顺序表:
为了更好的掌握ArrayList我们先来定义一个顺序表和接口,用顺序表这个类去实现接口,并重写接口中的所有方法;大家先来自己思考实现。顺序表最基础的两个属性就是数组和有效数组元素的大小
所需要实现的方法:
// 新增元素,默认在数组最后新增
public void add(int data);
// 在 pos 位置新增元素
public void add(int pos, int data);
// 判定是否包含某个元素
public boolean contains(int toFind);
// 查找某个元素对应的位置
public int indexOf(int toFind);
// 获取 pos 位置的元素
public int get(int pos);
// 给 pos 位置的元素设为 value
public void set(int pos, int value);
//删除第一次出现的关键字key
public void remove(int toRemove);
// 获取顺序表长度
public int size();
// 清空顺序表
public void clear() ;
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display() ;
重写方法的代码:(由于代码较长,博主觉得不适合全部放在这里,因为后面学习二叉树等时候代码会更长,但出于详细,才放这里,后面可能不放了(可以看gitee),所以路过的小伙伴可以给博主提建议(放还是不放))
import java.util.Arrays;
public class MyArray implements IExcese{
public int[] array = {};
public int size = 0;
public static final int INIT_SIZE = 5;
@Override
//要判断给出的下标是否合理所以我们要来抛出异常
public void add(int data) {
array = capitalArray();
array[size] = data;
size++;
}
@Override
//注意增加的元素不能隔空增加,比如3没有添加元素就直接在4下标添加,add可以理解为插入
public void add(int pos, int data) {
array = capitalArray();
if(pos<size && pos>=0) {
int mark = data;
for(int i = size - 1;i>pos;i--) {
array[i] = array[i - 1];
}
array[pos] = data;
size++;
}else {
throw new DataOverException("数组下标不符合规范");
}
}
@Override
public boolean contains(int toFind) {
for(int i = 0; i<size;i++) {
if(array[i] == toFind) {
System.out.println("下标位置为:" + i);
return true;
}
return false;
}
return false;
}
@Override
public int indexOf(int toFind) {
for (int i = 0; i < size; i++) {
if (array[i] == toFind) {
return i;
}
}
return -1;
}
@Override
public int get(int pos) {
if(pos<0 ||pos>=size) {
throw new DataOverException("下表不合理");
}else{
return array[pos];
}
}
@Override
public void set(int pos, int value) {
if(pos<0 ||pos>=size) {
throw new DataOverException("下表不合理");
}else{
array[pos] = value;
}
}
@Override
public void remove(int toRemove) {
int mark = 0;
int i;
for(i =0;i<size;i++) {
if(array[i] == toRemove) {
mark = 1;
}
}
if(mark ==1) {
for (int j = i; j < size-1; j++) {
array[i] = array[i+1];
}
size--;
}else{
System.out.println("没有该元素");
}
}
@Override
public int size() {
return size;
}
@Override
public void clear() {
for (int i =0 ;i<size;i++) {
array[i] = null;
}
size = 0;
}
@Override
public void display() {
for(int i = 0;i < size; i++) {
System.out.println(array[i]);
}
}
@Override
public String toString() {
return "MyArray{" +
"array=" + Arrays.toString(array) +
", size=" + size +
'}';
}
private int[] capitalArray() {
if (size == 0 ) {
return new int[INIT_SIZE];
}
else if(size == array.length) {
int newSize = size + 5;
//扩容数组,返回一个新数组
array = Arrays.copyOf(array,newSize);
return array;
} else {
return array;
}
}
}
大部分代码都比较为简单,我们挑几个来说就行;
1,添加元素的时候我们要判断是否需要扩容
扩容需要的方法Arrays.copyOf(),填两个参数,原数组和需要扩容元素的个数,返回的是原数组类型;
同时在指定位置添加的时候,要将元素后移;还要判断数组下标是否合理,不能小于0也不能大于等于size;
2,写异常
当下标不符合要求的时候我们可以写异常来抛出
3,数组清空
防止资源浪费我们要清空数组,由于数组是引用类型,所以我们清空的时候要将数组赋值为null
ArrayList:
ArrayList就类似数组,但为什么还有创建这个类,是因为当我们需要知道并运用这个数组的有效存储元素时,数组是无法满足的(比如数组整体有五个元素的大小,但实际上只存储了三个元素),而且ArrayList当中有很多方法可以使用;
同时ArrayList是泛型类,意味着你可以定义任意类型的数组
ArrayList的方法:
ArrayList方法的使用就和咱们实现的顺序表差不多,要想更加了解这个类当我们就要看其源码(最开始看源码是一件比较痛苦的事,但是我们必须要学会去了解以及深刨,而且上面顺序表的实现也很重要为了更好理解源码)
ArrayList的构造方法:
ArrayList有三个构造方法
1,带一个参数:
2 不带参数
这些字段均是ArrayList的属性
不带参数的时候创建一个空数组;此时没有给数组分配空间(使用add会分配);
3 参数为数组:
我们来解释一下这个参数是什么意思:
c是变量名,Collection要求传入的参数必须是Collection类型或者其子类,<? extends E>中?是通配符的意思,意思是传入的参数还必须是E或者E的子类,而E又指的是,泛型中传入的类型;
我们通过代码来更好地理解一下:其中<>中传入的类型就代表E,()中传入的数组就代表?;ArrayList是Collection的子类,所以arrayList满足第一个条件,arrayList中的元素均是String类型的,所以当传入参数的元素类型是String或者其子类的时候就可以编译成功;而第三行的E是Integer类型,String不是Integer的子类因此编译失败
ArrayList的add方法:
这是add的源码,其中调用的字段都在上张图有显示所以可以对照来看;
整个代码的思路是:
1 是否初始化,如果没有那么返回一个大小为10的数组;
2 如果初始化那么判断数组是否需要扩容,如果不需要那么返回原数组;如果需要那么进行扩容,在最后一步中判断是否扩容后数组元素是否超过了int的最大值,如果没有,那么扩容成功
3 每次扩容的时候会扩大1,5倍,x>>1,x这个值向右移1相当于除以2;
ArrayList的subList
传入两个参数,第一个是数组的起始下标,第二个是终点下标(左闭右开),相当于字符串的截取。但与字符串不同的是,字符串的改变是产生新的对象,但是subList截取后的数组和原数组指向的是同一个对象,因此改变其中一个数组的值另一个数组也会改变。
subList的返回类型是List,List是ArrayList的实现接口;
知识点补充:数据结构中常见的接口关系图
ArrayList的打印
1 重写toString后可以通过sout传入对象打印
2用for打印;
3用foreach这里包装类类型可以用基础类型接收,因为会自动拆包
4 迭代器,这里有个印象就行
二维数组:
ArrayList<ArrayList<Integer>>or<List<List<Integer>>>是二维数组,ArrayList的每个元素都是ArrayList<Integer>类型;