一、ArrayList简介
在集合框架中,ArrayList是一个普通的类,实现了List接口,具体框架图如下:
二、ArrayList使用
1、构造方法
不带参数
没有初始化,默认为空,只是一个数组引用
常量数组,没有分配内存,长度是0
因此不带参数的构造并没有给数组大小
带参数
初始化数组大小
如果参数是0的情况下,就会是空数组
如果是参数小于0就会抛出异常
另一个带一个参数的构造方法
参数Collection是一个接口,只要是实现了该接口的都可以进行传递
尖括号里的‘?’是通配符,尖括号里面可以写E或者E的子类
举例:
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
ArrayList<Integer> arrayList1 = new ArrayList<>(arrayList);
}
ArrayList实现了Collection接口,arrayList1的Integer是arrayList的Integer(或者Integer的子类),所以可以传递
2、add
直接尾部增加
如果刚开始数组是0,就通过grow方法扩容
如果刚开始数组是0,就进不去if语句,else语句就new数组
数组大小为minCapacity=size+1=1和DEFAULT_CAPACITY=10的最大值
所以当第一次分配内存就是10
如果刚开始数组不是0,进入if语句,初步预估按照1.5倍大小扩容
如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
将element放到指定index位置
addAll可以将一组数据一次性添加
3、remove
删除指定下标位置
remove删除值,将数据装箱
4、get
获取下标位置的元素
5、set
将下标位置元素设置为element
6、clear
清空数据
7、contains
判断o是否在线性表中
8、indexOf
返回第一个o所在下标
9、lastIndexOf
返回最后一个o的下标
10、subList
截取部分List,注意截取到的List是直接引用截取的位置,返回的是fromIndex的地址,因此改变新List就会改变原List
三、遍历ArrayList
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(1);
arrayList.add(2);
arrayList.add(4);
System.out.println(arrayList);
System.out.println("=======");
for (int i = 0; i < arrayList.size(); i++) {
System.out.print(arrayList.get(i)+" ");
}
System.out.println();
System.out.println("======");
for (Integer x:arrayList) {
System.out.print(x+" ");
}
System.out.println();
System.out.println("=======");
//迭代器
Iterator<Integer> it = arrayList.iterator();
while(it.hasNext()){
System.out.println(it.next()+" ");
}
System.out.println();
System.out.println("=======");
ListIterator<Integer> it2 = arrayList.listIterator();
while(it2.hasNext()){
System.out.println(it2.next()+" ");
}
System.out.println();
System.out.println("=======");
ListIterator<Integer> it3 = arrayList.listIterator(arrayList.size());//从最后位置打印
while(it3.hasPrevious()){
System.out.println(it3.previous()+" ");
}
System.out.println();
System.out.println("=======");
}
四、优缺点
缺点
1. ArrayList底层使用连续的空间,任意位置插入或删除元素时,需要将该位置后序元素整体往前或者往后搬移,故时间复杂度为O(N)
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
(链表弥补)
优点:
适合根据下标进行查找和更新的场景
五、例题
1、简单的洗牌算法
先来创建扑克牌
public class Card {
public int rank;//数字
public String suit;//花色
public Card(int rank,String suit){
this.rank = rank;
this.suit = suit;
}
@Override
public String toString() {
return "{" + rank + " " + suit + "}";
}
}
再来写一副牌的方法,包括创建一副新扑克牌,洗牌,抓牌
import java.util.*;
public class Cards {
public static final String[] suits = {"♥","♠","♣","♦"};
public List<Card> buyCard(){
List<Card> cardList = new ArrayList<>();
for (int i = 0; i < 4; i++) {
for (int j = 1; j <=13 ; j++) {
int rank = j;
String suit = suits[i];
Card card = new Card(rank,suit);
cardList.add(card);
}
}
return cardList;
}
//洗牌,两两交换
public void shuffle(List<Card> cardList){
Random random = new Random();
for(int i = cardList.size()-1;i>0;i--){
int rand = random.nextInt(i);
Card tmp = cardList.get(i);
cardList.set(i,cardList.get(rand));
cardList.set(rand,tmp);
}
}
//轮流抓牌
public void drawCards(List<Card> cardList){
List<Card> hand1 = new ArrayList<>();
List<Card> hand2 = new ArrayList<>();
List<Card> hand3 = new ArrayList<>();
List<List<Card>> hands = new ArrayList<List<Card>>();//列表里有三个人摸得牌,每个人手里的牌都放到列表里,相当于二维数组
hands.add(hand1);
hands.add(hand2);
hands.add(hand3);
for (int i = 0; i < 5; i++) {
for (int j = 0;j < 3;j++){
Card card =cardList.remove(0);//删除0下标表示抓牌
hands.get(j).add(card);
}
}
System.out.println("第一个人的牌:"+hand1);
System.out.println("第二个人的牌:"+hand2);
System.out.println("第三个人的牌:"+hand3);
}
}
import java.util.List;
public class test {
public static void main(String[] args) {
Cards cards = new Cards();
List<Card> cardList = cards.buyCard();//得到一副牌
System.out.println(cardList);
//洗牌
System.out.println("洗牌");
cards.shuffle(cardList);
System.out.println(cardList);
//抓牌
System.out.println("抓牌");
cards.drawCards(cardList);
System.out.println("剩下的牌");
System.out.println(cardList);
}
}
结果
2、杨辉三角
public List<List<Integer>> generate(int numRows){
List<List<Integer>> ret = new ArrayList<>();
List<Integer> list = new ArrayList<Integer>();
list.add(1);
ret.add(list);
for (int i = 1; i < numRows; i++) {
List<Integer> curRow = new ArrayList<>();
//第一个
curRow.add(1);
//中间
for (int j = 1; j < i; j++) {
List<Integer> preRow = ret.get(i-1);
int x1 = preRow.get(j);
int x2 = preRow.get(j-1);
curRow.add(x1+x2);
}
//最后一个
curRow.add(1);
ret.add(curRow);
}
return ret;
}
public static void main(String[] args) {
List<List<Integer>> list = generate(6);
for(int i =0;i< list.size();i++){
for (int j = 0; j < list.get(i).size(); j++) {
System.out.print(list.get(i).get(j)+" ");
}
System.out.println();
}
}
3、删除两字符串相同的字符
删除第一个字符串当中所有字符串2中所有的字符,使用ArrayList
public static List<Character> func(String str1,String str2){
List<Character> list = new ArrayList<>();
for (int i = 0; i < str1.length(); i++) {
char ch = str1.charAt(i);
if(!str2.contains(ch+"")){
list.add(ch);
}
}
return list;
}
public static void main(String[] args) {
System.out.println("str1:"+"hello every");
System.out.println("str2:"+"hey");
List<Character> list = func("hello everyone","hey");
for (char x:list) {
System.out.print(x);
}
System.out.println();
}