引言
1. List 接口
在说 ArrayList 之前,我们先来理解一下 List 接口是什么。
如下图,List 是一个接口,继承(拓展) Collection 接口。
而站在数据结构的角度来看,List 就是一个线性表,即 n 个具有相同类型元素的有限序列,在该序列上可以执行增删查改操作。
2. 注意
① List 是个接口,所有并不能直接通过 new 来实例化对象。如果要实现与 List 相关的结构,必须去实例化 List 的实现类。
② 在集合框架中,类 ArrayList 和 类 LinkedList 都实现了 List 接口。从数据结构的角度来看,它们俩就是顺序表和链表。而本篇博客主要讨论一下类 ArrayList 。
一、顺序表常用的方法
二、ArrayList 的扩容问题
1. 结论
① 如果 ArrayList 调用不带参数的构造方法,那么顺序表的大小为0,当第一次使用 add( ) 方法的时候,整个顺序表才变为10,当顺序表中的10个数据放满的时候,开始以1.5倍的方式进行扩容。
② 如果 ArrayList 调用带参数的构造方法,那么顺序表的大小就是你输入参数时的容量,当放满的时候,依然以1.5倍的方式进行扩容。
ArrayList<String> list1 = new ArrayList<>(); //不带参数的构造方法,初始容量为0 list1.add("a"); //当我们向 list1 中第一次添加的时候,底层代码就实现了初始化容量为10 ArrayList<String> list2 = new ArrayList<>(20); //带参数的构造方法,初始容量为20
2. 注意
这里我们需要注意一个点,ArrayList 终究还是一个类,我们由类实例化出来一个对象,那么我们对顺序表中的操作,都需要符合操作对象的规则。
所以在下面的程序清单1 中,当我们遍历顺序表的时候,和遍历数组的语法有很大不同。在数组中,我们可以直接通过数组名拿到对应的数组下标,从而获得对应的值,而在 ArrayList 底层的源代码中,Java 为我们提供了 get 方法来获取顺序表的下标。当然,这只是一个例子,所以以后在使用 Java 集合框架中的各种数据结构时,都要明确一点,我们操作的始终是某一个对象。
程序清单1:
import java.util.ArrayList; public class Test1 { public static void main(String[] args) { ArrayList<String> list1 = new ArrayList<>(); list1.add("a"); list1.add("b"); list1.add("c"); for (int i = 0; i < list1.size(); i++) { System.out.print(list1.get(i) + " "); } } } //输出结果:abc
三、与 ArrayList相关的题目
题目一
- 有若干学生(学生对象放在一个 List 中),每个学生有一个姓名(String)、班级(String)和考试成绩属性(double)某次考试结束后,每个学生都获得了一个考试成绩。遍历 list 集合,并把学生对象的属性打印出来。
程序清单2:
class Student{ private String name; private String classroom; private double score; public Student(String name, String classroom, double score) { this.name = name; this.classroom = classroom; this.score = score; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", classroom='" + classroom + '\'' + ", score=" + score + '}'; } } public class Test2 { public static void main(String[] args) { ArrayList<Student> students = new ArrayList<>(); students.add(new Student("Jack","1班",95.5)); students.add(new Student("Rose","2班",87.5)); students.add(new Student("Jim","1班",90.5)); System.out.println(students); } }
输出结果:
题目二
- 删除第一个字符串中出现第二个字符串中的字符
String str1 = " welcome to world ",String str2 = " come " 输出:wl t wrld
程序清单3:
public class Test3 { public static void main(String[] args) { String str1 = "welcome to world"; String str2 = "come"; ArrayList<Character> characters = new ArrayList<>(); for (int i = 0; i < str1.length(); i++) { char ch = str1.charAt(i); if(str2.contains(ch+"") == false){ characters.add(ch); } } for (Character character:characters) { System.out.print(character); } System.out.println(); } }
输出结果:
在上面的程序清单3中,str2.contains( ) 方法,需要提供 CharSequence 类型,可以将字符类型加一个空格,来进行判断。或者使用下面的 Set 集合也可以。
程序清单4:
import java.util.HashSet; import java.util.Set; public class Test4 { public static void main(String[] args) { String str1 = "welcome to world"; String str2 = "come"; Set<Character> set = new HashSet<>(); for (Character ch :str2.toCharArray()) { set.add(ch); } for (int i = 0; i < str1.length(); i++) { char ch = str1.charAt(i); if(!set.contains(ch)){ System.out.print(ch); } } System.out.println(); } }
输出结果:
题目三
- 有一个 List 中存放的是整型数据,要求使用 Collections.sort 对 List 进行排序
程序清单5:
public class Test5 { public static void main(String[] args) { ArrayList<Integer> integers = new ArrayList<>(); integers.add(4); integers.add(5); integers.add(1); integers.add(6); integers.add(3); Collections.sort(integers); System.out.println(integers); } }
输出结果:
题目四
leetcode 118 杨辉三角
程序清单6:
class Solution { public List<List<Integer>> generate(int numRows) { List<List<Integer>> ret = new ArrayList<>(); for (int i = 0; i < numRows; i++) { List<Integer> row = new ArrayList<>(); for (int j = 0; j <= i ; j++) { if(j==0 || j==i){ row.add(1); }else { row.add(ret.get(i-1).get(j-1)+ret.get(i-1).get(j)); } } ret.add(row); } return ret; } }
输出结果:
图解分析:
这一题在本人的第一篇博客中有详细解题思路,不过这一题的思想是面向对象的,所以可能很多人不习惯使用顺序表的 add( ) 方法和 get( ) 方法。
下面我主要说一下思想:
两层 for 循环,i 表示行,j 表示列,假设我们的数组名为 arr
那么有三个规律:
① arr [ i ] [ 0 ] = 1
② i 和 j 相等:arr [ i ] [ j ] = 1
③ i 和 j 不等:arr [ i ] [ j ] = arr [ i - 1 ] [ j - 1 ] + arr [ i - 1 ] [ j ]
上面是面向过程的写法,当我们将其转换成面向对象的写法时,我们只能先创建一个一维顺序表 row,将某一行装上元素,然后一行一行地放入二维顺序表 ret 中,通俗的讲,就是:通过下标将一维数组的数据装好了,就通过放入二维数组。