目录
一.前言:
Arraylist和Linkedlist都是继承自List接口,方法都基本相同——功能相同。但是他们的实现方式却不同。所以对于相同的操作,两者的效率可能也会不同。
扫描二维码关注公众号,回复: 15643776 查看本文章数据结构中的线性表有两种表现形式,一种按顺序存储的顺序表,一种链式存储的链表。而Arraylist就是以数组为基础,顺序表存储实现的。
LinkedList是是以链表为基础实现的。
这篇博客只是简单的实现Arraylist的增删改查功能,没有写构造方法和其他的属性和方法。如有需要改进的,还请指正。
二.ArrayList实现:
2.1思路分析:
1.Arraylist是以数组实现的,所以我们首先可以定义一个长度为10,类型为object的数组作为属性。
Object array[]=new Object[10];
2.1.1 add()方法:
add方法的作用是添加元素到集合,也就是把元素对象添加到数组中,这个怎么操作呢?
List集合是有索引确定位置的,我们每次完成一次赋值,那么数组的索引值加一。增加一个成员变量count用来计数增加的元素个数,同时也可以算作索引值。
代码:
@Override
public boolean add(Object o) {
grow();
System.out.println("扩容之后的长度"+array.length);
array[count]=o;
count++;
return true;
}
注意点:
add方法是有两个的,这个是重载另一个add方法:
作用是:把元素插入确定的索引位置。
插入到对应位置之后,那么后面的值就要对应的往后移,来个插入的元素腾出位置。用代码怎么表示这个后移的过程呢?
先看图:
从图中分析,插入位置后面的元素数组都要往后移,这个时候为了避免后移过程中,后面一个元素赋值给后后面元素,以此往后,把元素值给覆盖掉,我们从最后面开始后移。开始值为count(元素个数),当移到插入位置时结束,每一次移动减一。
代码:
@Override
public void add(int index, Object element) {
grow();
System.out.println("扩容之后的长度"+array.length);
for(int i=count;i>index;i--){
array[i+1]=array[i];
}
array[index]=element;
}
2.1.2 数组动态扩容:
这个只是我们基本数组的赋值操作,没有涉及到集合的核心——动态数组扩容机制。
动态数组扩容分析:
元素个数超过了数组长度时,我们这个时候就需要把数组长度扩大。所以首先判断元素个数是否大于数组长度,当大于时,创建一个新的数组,新的数组长度可以自己定义(最后是老数组的2倍),有了一个新的数组,可以把老的数组元素用for循环放到新数组中。最后也是最关键的一步,把老数组名(地址值)指向新数组名(地址值),我们用的时候还是老数组,但是老数组实际已经变成新数组了。
代码:
/*
数组的动态扩容
1.当我的数组添加的长度大于数组的定义的长度时,扩容
2.定义一个新数组,把新数组的长度增加为老数组长度的两倍
3.for循环将数组中的元素赋值到新数组中
4.把老数组的地址指向新数组
*/
public void grow(){
if(count>array.length){
//新数组的长度增加为老数组长度的两倍
Object[] newarray = new Object[array.length*2];
//数组中的元素赋值到新数组中
for(int i=0;i<array.length;i++){
newarray[i]=array[i];
}
//老数组的地址指向新数组
newarray=array;
}
}
2.1.3 set()方法:
set()方法作用:给定要修改值的索引,以及对象。只需要通过索引值,然后把对象赋值给该索引值位置,把原来的元素对象覆盖掉,最后返回对应位置的元素。
代码:
/*
修改
*/
@Override
public Object set(int index, Object element) {
array[index]=element;
return array[index];
}
2.1.4 contain()方法:
contain()方法作用:查找集合中有没有这个元素。可以遍历整个数组,使用equals方法,比较是否有相同的数组。
注意:
遍历的时候,遍历长度不能是数组长度,这样报NullPointerException错误,只能是遍历数组中元素个数(count变量)
代码:
/*
查找
*/
@Override
public boolean contains(Object o) {
//定义一个标记
boolean flag=false;
for (int i = 0; i <count ; i++) {
//当找到就返回true,否则返回false.
if(array[i].equals(o)){
flag=true;
}else{
flag=false;
}
}
return flag;
}
2.1.5 remove()方法 :
Arraylist支持两种删除方式:
1.按照下标删除
2.按照对象删除
先分析第一种,传入要删除的元素的下标,先通过索引值找到该元素,记录该元素,因为我们按照下标删除方法是返回删除元素。这时候直接调用System类中arraycopf方法,直接把该下标后面所有的元素往前移,也就是直接把后面的所有元素赋值到索引位置。
arraycopf方法:
将数组中指定的数据拷贝到另一个数组中。也可以直接拷贝到本数组中。
System.arraycopf方法中参数含义:
参数序号 参数名称 参数类型 参数含义 1 src Object 源数组 2 srcPos int 源数组索引起始位置 3 dest Object 目标数组 4 destPos int 目标数组索引起始位置 5 length int 复制元素个数
代码
/*
删除
*/
@Override
public boolean remove(Object o) {
//定义一个标记
boolean flag=false;
for (int i = 0; i <count ; i++) {
if(array[i].equals(o)){
remove(i);
flag=true;
}
}
return flag;
}
@Override
public Object remove(int index){
//删除指定位置的对象
Object oldvaule=array[index];
//求出目标数组的索引的位置
int num = count - index - 1;
//把index之后的元素全部赋值到nummoved位置
if (num > 0){
System.arraycopy(array, index+1, array, index,
num);
}
array[--count] = null;
return oldvaule;
}