数据结构:JAVA ArrayList

今天我们学习的是ArrayList。

目录

1.构造方法

2.ArrayList的数组

3.ArrayList的常见操作

4.数组的遍历 

5.数组的扩容

6.Collections.sort的排序

7.题目:删除1号字符串中的2号字符串

8.扑克牌的实现


ArraysList底层是一个顺序表,既然是顺序表那就是一个数组。我们可以看到,ArrayList实现了非常丰富的接口类型。我们接下来开始跟着源码学习。

1.构造方法

ArrayList()  :  这是一个无参构造

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(1);
        arrayList1.add(2);
        System.out.println(arrayList1);

}

ArrayList(Collection<? extends E> c)  

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(1);
        arrayList1.add(2);
        System.out.println(arrayList1);


        ArrayList<Integer> arrayList2 = new ArrayList<>(arrayList1);
}

 第二个构造方法里面,最后一句代码的意思是把arrayList1里面的元素放到arrayList2里面去。并且只要是Collection里面的方法都是可以的。

ArrayList(int initialCapacity)

这个构造方法说的是自定义数组的长度

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

2.ArrayList的数组

默认容量为10

 

elementData相当于就是顺序表背后的那个数组

 

有效的数据个数

 但是这个构造方法,它并没有分配数组的内存

也就是说elementData既然是没有大小的,那么怎么把数据放进去呢?

 这个时候我们点到add方法里面去:

    public boolean add(E e) {
                    //必须放一个E类型的数据
        ensureCapacityInternal(size + 1);  
        elementData[size++] = e;//这就是把数据放到最后一个元素的后面
        return true;
    }

我们再点到ensureCapacityInternal方法里面去,此时没有元素,那么size就是0。

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

minCapacity此时为1,我们再点到calculateCapacity方法里面去:

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

此时elementData为0,进入if条件句很明显有一个max方法赋值,那么最终返回的是DEFAULT_CAPACITY也就是10,那么把10作为 ensureExplicitCapacity的参数:

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

再点到grow函数中:

    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;//此时为0
        int newCapacity = oldCapacity + (oldCapacity >> 1);//仍然为0
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;     //此时对newCapacity赋值为10
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);那么到此才是给elementData赋值
    }

那既然现在大小为10,放第十一个元素的时候怎么扩容呢?在grow的第三行代码已经是采用了1.5倍的扩容。

也就是说第一个构造方法并不会给数组分配空间,但是第一次添加元素的时候会调用add方法此时再经过一系列的函数方法最终把数组初始化为10的大小。但是如果是第三种构造方法可以直接初始化数组的大小。

3.ArrayList的常见操作

 对于remove,先看E remove(int index),输入的index数据默认为删除的是index位置的元素,要使删除的是想要删除的数据,需要输入为 ArrayList.remove(new Integer(7));

4.数组的遍历 

1.for循环

        for (int i = 0 ; i < arrayList1.size();i++){
            System.out.print(arrayList1.get(i)+" ");
        }

2.for each遍历

        for (Integer x : arrayList1
             ) {
            System.out.print(x+" ");
        }

冒号的左边写类型和名字,右边写数组名

3.迭代器遍历

        Iterator<Integer> it = arrayList1.iterator();
        while(it.hasNext()){
            System.out.println(it.next()+" ");
            System.out.println("");
        }

迭代器基本使用方法如此,运用Iterator,每次读取的就是next的值,就可以一直打印下去

5.数组的扩容

ArrayList是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容

1. 检测是否真正需要扩容,如果是调用grow准备扩容

2. 预估需要库容的大小 初步预估按照1.5倍大小扩容 如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容 真正扩容之前检测是否能扩容成功,防止太大导致扩容失败

3. 使用copyOf进行扩容

6.Collections.sort的排序

public class TestDemo {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList<>();
        arrayList.add(new student("张三",19,88.5));
        arrayList.add(new student("李四",23,89.5));
        arrayList.add(new student("王五",20,85.5));

        for(int i = 0 ; i < arrayList.size();i++){
            System.out.println(arrayList.get(i) + " ");
        }
        Collections.sort(arrayList);
        
    }
    
}

我们在运用ArrayList输出一个学生的姓名、年龄、分数的时候,对于分数的排序我们可以用到Collections.sort来进行排序。但是如果直接把arraylist放到括号里面会发现编译器报错了。

    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }

我们发现这个类型extends Comparable,所以我们需要在class student后面写上:

class student implements Comparable<student>{}

同时我们还需要重新toString方法:

    @Override
    public int compareTo(student o) {
        return (int)(this.score - o.score);
    }

这样就可以以分数为序列进行排序了。

7.题目:删除1号字符串中的2号字符串

例如:1:welcome to China  2:come

输出:wl t hina

具体思路就是用ch.charAt接收每一个str1里面的字符,然后与str2对比。若没有对比成功,那么就在arrayList中加上这个字符。但是发现str2.contains(ch)报错了。这时只需要在ch后面加上一个“ ”就能解决:

    public static void func(String str1,String str2){
        ArrayList<Character> arrayList = new ArrayList<>();
        for (int i = 0; i < str1.length(); i++) {
             char ch = str1.charAt(i);
             if(!str2.contains(ch+"")){
                 arrayList.add(ch);
             }
        }
    }

string类型加上一个“ ”就变成了一个字符串类型,这是一个小技巧。

8.扑克牌的实现

先新建一个poker类,定义好相关的基础信息以及构造方法等等

public class Poker {
    public String suit;//花色
    public int rank;//点数

    public Poker(String suit, int rank) {
        this.suit = suit;
        this.rank = rank;
    }
    public String getSuit() {
        return suit;
    }

    public void setSuit(String suit) {
        this.suit = suit;
    }

    public int getRank() {
        return rank;
    }

    public void setRank(int rank) {
        this.rank = rank;
    }

    @Override
    public String toString() {
        return suit+" "+rank;//重写toString方法
    }
}

然后再建一个pokers类,写出花色和最开始的方法:buyPokers:

public static List<Poker> buyPokers(){
        List<Poker> pokerList = new ArrayList<>();//我们在此新建一个ArrayList
        for (int i = 0; i < 4; i++) {                //i的取值为四种花色
            for (int j = 0; j < 13; j++) {           //j的取值为13个不同的大小
                String suit = SUITS[i];              //suit就是新建的花色
                Poker poker = new Poker(suit,j);     //此时poker已经是一张牌了
                pokerList.add(poker);                //把一张poker添加到pokerlist里面去
            }
        }
        return pokerList;                            //最后再返回
    }

接着我们需要洗牌,用到的方法是shuffle和swap:

    
    public static void shuffle(List<Poker> pokerList//指的是传进来的是这种类型的这个变量) {
        Random random = new Random();
        for (int i = pokerList.size()-1; i > 0 ; i--) {   //i初始比数组大小小1,再逐个递减
            int index = random.nextInt(i);                //定义index就是i的随机值
             swap(pokerList,i,index);                     //此时再传入swap函数里去
        }
    }
    public static void swap(List<Poker> pokerList,int i,int j){
        Poker tmp = pokerList.get(i);                     //定义tmp为第三交换变量
        pokerList.set(i,pokerList.get(j));                //get(j)的元素和i交换
        pokerList.set(j,tmp);                             //tmp和j交换
    }

最后就是3个人揭牌,每个人揭5张牌:

    public static void main(String[] args) {
        List<Poker> pokerList = buyPokers();
        System.out.println("买牌"+ pokerList);
        shuffle(pokerList);
        System.out.println("洗牌"+ pokerList);

        List<Poker> hand1 = new ArrayList<>();     //这里的hand1,2,3就代表着三个人
        List<Poker> hand2 = new ArrayList<>();
        List<Poker> hand3 = new ArrayList<>();

        List<List<Poker>> hand = new ArrayList<>();//注意,这里的List<List<Poker>>代表的是在这个List里面,每一个元素都是List类型,也就是说这是一个有元素类型是List,大小是3的List
        hand.add(hand1);     //接口里面的add方法,把hand1,2,3添加到hand里面去
        hand.add(hand2);
        hand.add(hand3);

        for (int i = 0; i < 5; i++) {                       //i就是5张牌
            for (int j = 0; j < 3; j++) {                   //j就是三个不同的人
                List<Poker> handtmp = hand.get(j);          //get(j)就是拿到不同的手,代表着 
                                                                                   不同的人
                handtmp.add(pokerList.remove(0));           //handtmp就是拿到的就是不同的人, 
                                                                     添加进去就是这个人的牌
            }     //pokerList.remove(0)  因为这个永远代表着数组的第一个元素,所以正好添加进去的元素和数组的元素拿出来可以共用一条语句
        }
        for (int i = 0; i < hand.size(); i++) {
            System.out.println("第"+(i+1)+"个人的牌是"+hand.get(i));
        }
        System.out.println("剩余的牌是:"+pokerList);

    }

ArrayList有一定难度,但是这才只是数据结构的开始。

革命尚未成功,同志仍需努力。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值