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、付费专栏及课程。

余额充值