数据结构初阶:Java中的ArrayList

ArrayList的的底层是一个顺序表。

顺序表是用一段地址连续的单元来依次存储数据元素的线性结构,他一般采用数组进行存储。可以在顺序表上进行增删改查。

1.ArrayList简介

ArrayList是一个普通的类,它底层是一个动态顺序表,实现了List接口。

(不是全部关系)

重要说明:

1.ArrayList是以泛型方式实现的,使用时必须要先实例化。

2.ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问

3.ArrayList实现了Serializable接口,表明ArrayList是支持序列化的

  1. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
  2. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表
    6.ArrayList实现了Cloneable接口,表明ArrayList是可以clone的

2.ArrayList的使用

2.1ArrayList的构造方法

方法: 解释:

ArrayList() 无参构造

ArrayList(Collection<? extends E> c) 利用其他Collection构建ArrayList

ArrayList(int initialCapacity) 指定顺序表初始容量

示例:

java 复制代码
import java.util.ArrayList;

public class Test1 {
    public static void main(String[] args) {
        //这样创建没什么特别的....
        //因为ArrayList实现了List接口,所以用List来接收也行
        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(1);//添加
        list1.add(2);
        list1.add(3);

        //ArrayList也实现了Collection
        ArrayList<Integer> list2 = new ArrayList<>(list1);
        System.out.println(list2); //list2没add(),却打印[1,2,3]

        //这也没什么特别的
        ArrayList<Integer> list3 = new ArrayList<>(10);//顺序表初始空间为10
        
    }
}

2.2ArrayList常见操作

ArrayList提供的方法很多,但常见的方法如下。

ArrayList可以进行增删查改,改、查的时间复杂度为O(1)(底层是一个数组),但增、删的时间复杂度可达O(n) 。

2.2.1ArrayList底层

ArrayList中会有int usedSize记录有效元素个数

当我们使用add()进行插入时,会出现以下请况;添加元素---》usedSize++

同理,当我们进行remove(删除)时,后面的值会依次向前补,usedSize--;虽然原来数组末尾的值还存在,但是ArrayList中遍历有效数组是依靠usedSize。

2.2.2ArrayList的遍历

java 复制代码
List<String> list = new ArrayList<>();
        list.add("1");
        list.add("12");
        list.add("123");

        //法一:for循环遍历
        for (int i=0;i< list.size();i++){
            System.out.println(list.get(i));
        }

        //法二:for-each循环遍历
        //ArrayList的底层是数组,所以可以这样操作
        for(String str:list){
            System.out.println(str);
        }

        //法三:借助迭代器
        Iterator it = list.iterator();//因为AL实现了Iterable,所以它可以所以迭代器遍历
        while(it.hasNext()){
            System.out.print(it.next() + " ");
        }

2.3ArrayList的扩容机制

有人或许会在2.2.1发出疑惑:

  1. 如果没给ArrayList指定数组大小,那数组初始大小为多少?
  2. 如果数组满了,再添加元素会报错吗?

解答:

当我们未给ArrayList指定数组大小时,它底层的数组大小就是0;只不过在add()内会判断有效元素个数是否与数组大小相同,相同则扩容

因此ArrayList的底层才会叫做动态顺序表!数组会自动扩容。

3.ArrayList实操

实现简单的洗牌算法:

提醒

  • List<Card> list = new ArrayList<>();// 的意思是list的底层数组只能放Card类型的数据
  • List<List<Card>> list = new ArrayList<>(); // 的意思是只能放List<Card>类型的数据,可以想象成二维数组。
java 复制代码
public class Card {
    public int rank; // 牌面值
    public String suit; // 花色

    @Override
    public String toString() {
        return "Card{" + rank + suit +
                '}';
    }
}


//总结就是 买牌,打乱牌(shuffle和swap方法都是用来打乱牌的),发牌

import java.util.List;
import java.util.ArrayList;
import java.util.Random;
    public class CardDemo {
        public static final String[] SUITS = {"♠", "♥", "♣", "♦"};
        // 买一副牌
        private static List<Card> buyDeck() {
            List<Card> deck = new ArrayList<>(52);
            for (int i = 0; i < 4; i++) {
                for (int j = 1; j <= 13; j++) {
                    String suit = SUITS[i];
                    int rank = j;
                    Card card = new Card();
                    card.rank = rank;
                    card.suit = suit;
                    deck.add(card);
                }
            }
            return deck;
        }
        private static void swap(List<Card> deck, int i, int j) {
            Card t = deck.get(i);
            deck.set(i, deck.get(j));
            deck.set(j, t);
        }
        private static void shuffle(List<Card> deck) {
            Random random = new Random();
            for (int i = deck.size() - 1; i > 0; i--) {
                int r = random.nextInt(i);
                swap(deck, i, r);
            }
        }
        public static void main(String[] args) {
            List<Card> deck = buyDeck();
            System.out.println("刚买回来的牌:");
            System.out.println(deck);
            shuffle(deck);
            System.out.println("洗过的牌:");
            System.out.println(deck);
// 三个人,每个人轮流抓 5 张牌
            List<List<Card>> hands = new ArrayList<>();
            hands.add(new ArrayList<>());
            hands.add(new ArrayList<>());
            hands.add(new ArrayList<>());
            for (int i = 0; i < 5; i++) {
                for (int j = 0; j < 3; j++) {
                    hands.get(j).add(deck.remove(0));
                }
            }
            System.out.println("剩余的牌:");
            System.out.println(deck);
            System.out.println("A 手中的牌:");
            System.out.println(hands.get(0));
            System.out.println("B 手中的牌:");

            System.out.println(hands.get(1));
            System.out.println("C 手中的牌:");
            System.out.println(hands.get(2));
        }
    }
相关推荐
JH30732 小时前
10分钟理解泛型的通配符(extends, super, ?)
java·开发语言·windows
试试勇气3 小时前
算法工具箱之双指针
数据结构
在等晚安么3 小时前
力扣面试经典150题打卡
java·数据结构·算法·leetcode·面试·贪心算法
Fency咖啡3 小时前
Spring进阶 - Spring事务理论+实战,一文吃透事务
java·数据库·spring
Tony Bai3 小时前
【Go模块构建与依赖管理】01 前世今生:从 GOPATH 的“混乱”到 Go Modules 的“秩序”
开发语言·后端·golang
Zxxxxxy_3 小时前
【MYSQL】增删改查
java·数据库·mysql
菜鸟的迷茫3 小时前
线程池中的坑:线程数配置不当导致任务堆积与拒绝策略失效
java·后端
缺点内向3 小时前
Java 使用 Spire.XLS 库合并 Excel 文件实践
java·开发语言·excel
asdfsdgss3 小时前
多项目共享资源:Ruby 定时任务基于 Whenever 的动态扩缩容
java·网络·ruby