ArrayList与顺序表(很详细)

一.ArrayList

        1.1.前言

        在使用这些方法之前,我们可以想一下,如果这些方法让我们自己实现它的功能我们应该怎么写呢?


      1.2  自己写的add:功能

        

        isfull方法是来判断数组是否满了,grow是来扩容的,this.arr是需要扩容的数组,2*arr.length是扩容的大小。

        

        通过数组来存放你add方法的值。

         这个是可以填自己指定的位置。

        

        checkpos方法是防止错误输入的。

而checkadd是我们自己写的一个异常。

        我们输入一个越界的。       

        就会报出异常。


    1.3 自己写的contains方法

        通过遍历数组的形式来找是否存在某个值。


1.4 自己写的indexof方法

        这个方法数用来等到你想要的元素的下标的。

        

        通过isempty方法来判断数组是否为空。

        isemptyexption是我们写的自定义空值异常的方法。


        1.5 自己写的get方法

        

        返回某个下标的元素。


1.6 自己写的set方法

        

        通过输入你要改的下标和值,就可以了。


        1.7 自己写的remove方法

        通过上面的indexof方法找到你要修改的元素的下标,在通过数组覆盖的方式移除那个值。


1.8 自己写的size方法

        

        放回数组的长度。


1.9 自己写的clear方法

        该方法的作用是清屏的。


1.10 自己写的display方法

        

        遍历数组。

        这些方法是我们通过自己对这些方法的表层理解来自己写的,实际内部原理很复杂,这可以帮助我们简单理解一下。


2.1 Arraylist的简介

        在集合框架中,ArrayList是一个普通的类,实现了List接口,具体框架图如下:

    说明:

1. ArrayList是以泛型方式实现的,使用时必须要先实例化
2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
3. ArrayList实现了Cloneable接口,表明ArrayList是可以clone
4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
5. Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList。
6. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

2.2 Arraylist的使用

        2.2.1 Arraylist的构造方法

        
        这就是空参构造,可以访问所有的方法。
        
        第二个构造方法就是可以加一个泛型。
        
        Integer是泛型的一种,它是一种泛型,而第二个newlist对象则是以list为参数给了newlist。
        
        第三种是指定数组的初始容量的。
        数组越界异常了,你指定的数组大小是6,下标是0到5,你现在访问下标为7的,肯定会越界的。

        2.3 Arraylist常用的一些方法


        2.3.1 add方法

        

        通过list输出结果说明Arraylist也有自己的toString的方法,还要两个可以自己试一下,很简单。


        2.3.2 addall方法

                

        插入的对象得是Arraylist对象。


2.3.3 get方法

        

        跟数组一样就是拿元素的。

        


        2.3.4 set方法

        

        修改已经存在的值,无法建立新的值。

注意:

        set 方法用于修改指定索引位置的元素,不能用于创建新的元素。如果指定的索引位置超出了当前列表的范围,就会抛出 IndexOutOfBoundsException 异常。

        如果您想要向列表中添加新元素,应该使用 add 方法。

         其他的方法大家感兴趣都可以自己试试,我就不一一列举了。


        2.2.5 remove方法

        

        它有两种用法,如图所示,一种是输入元素的索引来删除对象,一种则是通过内容删除对象。


        2.4 Arraylist的遍历

                第一种遍历

        跟数组一样。

        第二种遍历借助foreach遍历

        

        

        第三种通过迭代器来遍历

        

        如图所示,it表示的是一个迭代器对象。

        hasnext方法

        它的作用就是让光标移动到下一个的,并判断下一个位置是否存在元素,存在返回true,没有返回false。

        

        开始在最上面,你可以理解为光标在下表为-1的位置当然它是不存在-1的,就是0之前的那个位置。进去一次,向后移动一个位置。

        next方法

        获取当前位置的元素并返回。

        


        2.4 Arraylist的自动扩容机制

        下面的代码有问题吗?

              

        它是怎么进行扩容的?

        

        在 Java 中,ArrayList 的底层使用了一个数组来存储元素。当使用 add 方法添加元素并且当前数组容量不足时,ArrayList 会自动进行扩容操作。

        默认情况下,创建一个 ArrayList 对象时,其初始容量为 10 。当添加元素导致数组已满时,扩容的策略通常是将当前容量增加约 50% 。也就是说,如果当前容量为 n ,扩容后的新容量大致为 n + n / 2 。

具体的扩容过程大致如下:

  1. 创建一个新的更大容量的数组。
  2. 将原数组中的元素复制到新数组中。
  3. 将新添加的元素放入新数组的合适位置。

        这种自动扩容的机制为开发者提供了便利,使得在使用 ArrayList 时无需过多关注底层数组容量的管理,但也需要注意频繁扩容可能会影响性能,特别是在预计会存储大量元素的情况下,可以在创建 ArrayList 时指定一个合适的初始容量。

如何手动设置 ArrayList 的初始容量?

ArrayList 在扩容时,复制元素的效率如何?

除了 ArrayList,还有哪些集合类提供了自动扩容的功能?

        


2.5   扩充的知识

        接口对象

        

        Arraylist实现的还要一些接口,也可以通过接口来实例化对象。

        

        它俩的区别:

       1. 类型声明的明确性:

        在第一种方式中,明确声明了变量 list 的类型为 ArrayList 。

        在第二种方式中,声明变量 list1 的类型为更通用的接口 List ,实际创建的对象是 ArrayList 。

        2.灵活性:

        当使用 List 接口类型进行声明(如第二种方式)时,如果后续因为需求变更需要将实现类从 ArrayList 更换为其他实现了 List 接口的类(如 LinkedList ),代码修改的范围较小,只需要修改创建对象的那一行代码,而使用该变量的其他代码无需修改。

        因为 ArrayList 实现了 List 接口中定义的所有方法,无论通过 ArrayList 类型声明还是通过 List 接口类型声明并创建 ArrayList 对象,都能够调用 List 接口中定义的那些方法。

        sublist方法

        

        接收值是List类型的。

        表示把索引为[0,2)的内容给List<Integer> l这个对象,左闭右开的形式。

        结果

        

迭代器知识的扩充

        我们上面也讲到了通过迭代器也可以遍历Arraylist对象的内容

        接下来我们再讲一下ListIterator这个接口。

        它比Iterator多了几个方法,我们举出几个常用的。

        

        

        它和上面的hasnext方法不同的是,它是从后往前遍历输出的,hasnext是从前往后遍历输出的。

        二维List

        

        List中套上一个List。

        赋值方式

        第一种

        直接给这个类似二维的一个List<Integer>对象。

        结果

        

        第二种

        

        通过Arrays的asList方法给这个二维的赋值。

        结果

        

        遍历方法

        第一种

        跟二维数组差不多一样    

        结果

        

这个Arrays.aslist方法不能和add方法联合使用。

        什么意思呢?

        这样没有任何问题。

        

        这样就有问题了。

        报错了。

        你可以理解为,当你用aslist赋值完成之后,这个数组的大小就锁死了,无法添加元素。

        注意

        list.add(Arrays.asList(val1 + val)) 这种方式不是在已有内层列表的合适位置添加值,而是直接向外层的 list 中添加一个新的内层列表。

        在 List<List<Integer>> list 中,list 是外层列表。

        而 list 中的每个元素,比如 list.get(0) 、list.get(1) 等,这些元素本身也是一个 List<Integer> ,它们被称为内层列表。

        简单理解就是每一行是一个外层,每一行中的值是内层。

        第二种

        

        通过for-each语句遍历。跟数组差不多一样

        结果

        

        第三种

        

        通过迭代器的方式遍历。

        先通过第一层while循环取出我们想要输出的。

        然后通过第二层循环进行输出。

        结果

        

        第四种

        和第三种基本一样,只是把第三种的Iterator<Integer> list = listInteger.next().listIterator();拆开来写了。

        2.6 练习

        第一个练习

        去除str中的str1所包含的字母。

        例如:str=“abcda” , str1=“ab”。

        去除之后就是“cd”。

        三种作法。

        第一种

        通过把字符串变成字符数组,然后利用字符数组的形式进行操作。

        

        第二种方法

        

        第三种利用我们所学的数据结构

        

        为什么会报错呢?

        

        CharSequence表示要传入一个字符串形式,而不是字符形式。

        怎么解决呢?

        如下图

        

        通过这个想法来解决。

        如下图:

        

        这样就能把字符变成字符串的形式了。

        

        第二个练习:杨辉三角

        要求:通过我们学的打印出来杨辉三角。

   

        这是第一部分,创建一个二维的List对象,然后放入一个对象list2,他就会把杨辉三角的第一行完成。

        a是控制杨辉三角的行数的。

        第一层for循环,创建一个list1对象,先add(1),是完成每次杨辉三角的第一列.

        用一个list3对象来接收一下list的内层,通过下面的两个int类型的变量来接收值。

        把值给到list1对象中,就得到了这一部分内容。

        

        最后的list1.add(1)是完成每一行的最后一个元素的。

        最后把全部的值给到list。

        通过我们上面教的方法按照要求打印出来。

        就是这个效果了。

        

第三个练习(扑克牌)

        3.1 买牌

        要求就是先得到一副扑克牌才行。

        

        这是我们的牌库。

        

        String数组来表示花色,通过buycard方法来得到扑克牌,先创建一个Arratlist动态数组,一共52张牌(不含大小王),13个数字和4个花色,通过for循环来控制。

        通过rank拿到数字,s拿到花色,实例化对象放到动态数组中,最后返回。

        

        结果:

        

        后面太多了,没有截完图。

        买完牌之后我们就可以开始玩了。

        3.2 打牌

        打牌之前我们要洗牌。

        接下来我们就写一个洗牌的操作。

        3.2.1 洗牌

        

     int index = rd.nextInt(i); 这段代码通常是从一个随机数生成器 rd 中获取一个介于 0(包含)和 i(不包含)之间的随机整数,并将其赋值给变量 index 。

        通过生成随机数和你的i位置的值交换一下。

        洗完牌之后,我们就要开始发牌了。

        3.2.2 发牌

        

        创建三个玩家list,list1,list2,通过if语句控制发牌,先发一号玩家。

        

        也可以这样发牌,通过一个二维动态数组,把三个玩家传进去,然后通过双层for循环,第一层代表每个玩家有多少个牌,第二层代表玩家的数量。

        通过remove来得到你去除的对象,他会返回一个card类型的值,然后通过card类型的变量来接收这个值,每次去除完成之后,后一个元素的索引-1,所以就是按照顺序,你要拿的牌的索引一直为0;

        

        

        通过冒泡排序来整理牌的顺序,从小到大。

        

        这个是用来判断二号玩家要不要地主,不要就问下一家,也就是三号玩家。

         这个是用来判断三号玩家要不要地主,不要就问下一家,也就是一号玩家。

        这个是用来判断一号玩家要不要地主,不要就问下一家,也就是二号玩家。

        只要两家玩家不要,第三家必须要,有种强制的感觉。

        

        在整理一下牌。

        这个的作用就是来生成一个随机数,a是来代表花色的,b是来代表牌的大小的,有三张地主。这是我自己随便写的一个东西,和现实的斗地主可能不同。

        

最后:结束语

        感谢大家的查看,希望可以帮助到大家,做的不是太好还请见谅,其中有什么不懂的可以留言询问,我都会一一回答。  感谢大家的一键三连。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值