在Java中 : 它提供了许多集合类, 今天我们看一下ArrayList类.
它的底层其实就一个数组.在下面我写了一些ArrayList类中的一些常用的方法,大家可以自己先写一下.具体解法在后面 :
public class MyArrayList {
private int[] elem;
private int usedSize; // 存储了多少个有效的数据
public static final int DEAULT_SIZE = 10;
// 默认构造方法
MyArrayList(){
this.elem = new int[DEAULT_SIZE]; // 默认情况下我们给它底层容量设置为10
}
// 新增元素,默认在数组最后新增
public void add(int data) { }
// 在 pos 位置新增元素
public void add(int pos, int data) { }
// 判定是否包含某个元素
public boolean contains(int toFind) { return true; }
// 查找某个元素对应的位置
public int indexOf(int toFind) { return -1; }
// 获取 pos 位置的元素
public int get(int pos) { return -1; }
// 给 pos 位置的元素设为 value
public void set(int pos, int value) { }
//删除第一次出现的关键字key
public void remove(int toRemove) { }
// 获取顺序表长度
public int size() { return 0; }
// 清空顺序表
public void clear() { }
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display() { }
}
接下来我们一个一个看下它的方法是怎么实现的 :
1.display() : 用来打印的 我们要通过usedSize来确定 i 要打印多少次,也就是它的有效数据.
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display() {
for (int i = 0; i < usedSize; i++) {
System.out.print(elem[i] + " ");
}
System.out.println();
}
2.contains() : 用来判断是否包含某个元素. 我们也是通过usedSize来一一判断.
// 判定是否包含某个元素
public boolean contains(int toFind) {
for (int i = 0; i < usedSize; i++) {
if (elem[i] == toFind) {
return true;
}
}
return false;
}
3. add(int data) : 在添加元素的时候,要注意一点,如果usedSize 的值跟elem.length的值一样的话,证明数组满了,我们需要扩充数组.
// 新增元素,默认在数组最后新增
public void add(int data) {
if (this.usedSize == elem.length) {
expand();
}
this.elem[this.usedSize] = data;
this.usedSize++;
}
//扩大1倍
public void expand () {
this.elem = Arrays.copyOf(this.elem,this.elem.length * 2);
}
4.add(int pos, int data) : 在某个位置去插入元素data :
1.pos位置必须合法.(不能为负数 不能超过usedSize).
2.如果要插入的位置等于数组的长度(证明数组满了) 那么我们就要扩充数组.
3.到第三步,我们就可以去放了,从最后一个元素依次往后放,注意边界值. i >= pos.(要把pos位置的空腾出来).
4.把data放入pos位置.
5.记得this.usedSize++;
// 在 pos 位置新增元素
public void add(int pos, int data) throws PosException{
//如果下标异常的话 抛异常
if (pos < 0 || pos > this.elem.length) {
throw new PosException("下标越界");
}
if (usedSize == this.elem.length) {
expand();
}
for (int i = usedSize - 1; i >= pos; i--) {
this.elem[i + 1] = this.elem[i];
}
this.elem[pos] = data;
this.usedSize++;
}
//异常类
public class PosException extends RuntimeException{
public PosException() {
super();
}
public PosException(String message) {
super(message);
}
}
5. indexOf() : 查找某个元素对应的位置.
// 查找某个元素对应的位置
public int indexOf(int toFind) {
for (int i = 0; i < usedSize; i++) {
if (elem[i] == toFind) {
return i;
}
}
return -1; // 因为数组中没有-1下标
}
6. get() : 获取pos位置的元素 : 注意判断pos位置是否是有效的
// 获取 pos 位置的元素
public int get(int pos) {
//如果下标异常的话 抛异常
if (pos < 0 || pos >= this.elem.length) {
return -1;
}
return this.elem[pos];
}
7. set () : 改变pos位置的值.
// 给 pos 位置的元素设为 value
public void set(int pos, int value) {
//如果下标异常的话 抛异常
if (pos < 0 || pos >= this.elem.length) {
throw new PosException("下标越界");
}
this.elem[pos] = value;
}
8. remove () : 删除第一次出现的关键字key :
1.先通过indexof() 判断一下这个值在数组中的下标
2.如果这个值存在,那么就返回的是它的地址,否则是-1
3.通过循环,从返回的下标,到 i < usedSize - 1; (注意这个边界值)
4.最后注意this.usedSize--;
//删除第一次出现的关键字key
public void remove(int toRemove) {
int index = indexOf(toRemove);
if (index == -1) {
return;
}
for (int i = index; i < usedSize - 1; i++) {
this.elem[i] = this.elem[i + 1];
}
this.usedSize--;
elem[usedSize] = 0;
}
9.size() : 获取顺序表的长度 :
// 获取顺序表长度
public int size() {
return this.usedSize;
}
10. clear() : 清空顺序表 :
// 清空顺序表
public void clear() {
this.usedSize = 0;
}
这里如果顺序表里面操作的是引用数据类型,那么就需要把它每个元素置为空.

这就是我们经常要使用的一些ArrayList集合类里面的一些方法.
总结 :
顺序表的缺点 : 插入元素的时候,如果插入的位置是0下标,那么它的时间复杂度就达到了O(n).
删除也是,O(n)
因此顺序表不是很适合 频繁的对数据进行插入和删除的场景.
它比较适合给定下标 然后查找.
接下来我们来看一下,Java中的Arraylist类
ArrayList是以泛型方式实现的,使用时必须要实例化.
ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表.
我们先来了解一下它的构造方法

1.无参构造.当我们去new一个ArrayList对象时,它会默认给我们分配内存且大小为10.
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
}
2.我们也可以给它传过去一个内存大小.
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>(15);
}
3.也可以传过去一个类型(实现了Collection接口的类 并且它是E(泛型)的本身或者是子类)
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(19);
list.add(18);
ArrayList<Integer> arrayList = new ArrayList<>(list);
System.out.println(arrayList);
}
}
运行结果为 :

这些是ArrayList的一些常用方法 :

我们重点来看一下最后一个方法 : 它的作用是截取
public class Test {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(19);
list.add(18);
list.add(12);
list.add(17);
list.add(11);
//截取[2,4)的值 返回值类型是List<Integer>
List<Integer> list1 = list.subList(2, 4);
//我们来吧list1中的0下标的值改为999 也就是把12改为999
list1.set(0,999);
System.out.println(list1);
}
}
运行结果 :

重点来了 :
这时候我们去打印一下list的值 :
public class Test {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(19);
list.add(18);
list.add(12);
list.add(17);
list.add(11);
//截取[2,4)的值 返回值类型是List<Integer>
List<Integer> list1 = list.subList(2, 4);
//我们来吧list1中的0下标的值改为999 也就是把12改为999
list1.set(0,999);
System.out.println(list1);
System.out.println(list);
}
}
运行结果 :

是的,你没看错,其实通过这个方法截取下来的部分,和原来数组共用了一块地址.

最后说一下ArrayList的遍历 :
1.通过toString方法来输出 :
public class Test {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(123);
list.add(678);
System.out.println(list);
}
}

2.使用循环 使用get方法 :
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(123);
list.add(678);
//System.out.println(list);
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
}

3. foreach :
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(123);
list.add(678);
//System.out.println(list);
// for (int i = 0; i < list.size(); i++) {
// System.out.print(list.get(i) + " ");
// }
for (Integer a: list) {
System.out.print(a + " ");
}
}

4. 迭代器 :
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(123);
list.add(678);
//迭代器
ListIterator<Integer> it = list.listIterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}


文章详细介绍了Java中ArrayList类的基本实现,包括构造方法、add、contains、indexOf、get、set、remove、size、clear等方法的实现逻辑。还提到了ArrayList的动态扩容机制以及遍历ArrayList的几种方式。并讨论了ArrayList作为顺序表的优缺点,特别是在插入和删除操作上的效率问题。
1316

被折叠的 条评论
为什么被折叠?



