• 数据结构 - ArrayList - 动态修改的数组


    目录

    实现一个通用的顺序表

    总结

    包装类

    装箱 / 装包 和 拆箱 / 拆包

    ArrayList 与 顺序表

    ArrayList基础功能演示

    add 和 addAll ,添加元素功能

    ArrayList的扩容机制

    来看一下,下面的代码是否存在缺陷

    模拟实现 ArrayList

    add 功能

    add index 

    add 两种用法的效果图

    remove 功能 - 删除删除遇到的第一个 指定元素

    remove 功能 - 删除 index 位置元素

    get - 获取指定下标位置元素

    set - 将指定的下标的元素,置换为 指定的数据

    clear - 清空

    contains - 判断 指定元素 是否在线性表中

    indexOf 和 lastIndexOf ,直接搬原码(注意indexOf 是前面写了的(只要把private改成public就行),直接搬lastIndexOf)

    总结:

    ArrayList 实践案例 - 扑克牌

    发牌 / 揭牌


    实现一个通用的顺序表

    顺序表的功能不是重点,我们在这里只是粗略实现一下顺序表的功能,重点在泛型

    准备工作,相信大家都看得懂。

    1. class MyArrayList{
    2. private int[] elem;// 建立数组
    3. private int usedSize;// 有效元素个数
    4. // 构造方法
    5. public MyArrayList(){
    6. this.elem = new int[10];// 默认数组初始容量为 10
    7. }
    8. // 添加元素
    9. public void add(int val){
    10. this.elem[usedSize] = val;
    11. }
    12. // 得到指定位置的元素
    13. public int get(int pos){
    14. return this.elem[pos];
    15. }
    16. }
    17. public class Test {
    18. }

    但是这个代码并不通用,只能存储一种数据类型(int)。

    总结

    1. 泛型是作用在编译期间的一种机制,即运行期间没有泛型的概念。
    2. 泛型代码在运行期间,就是我们上面提到的,利用 Object 达到的效果(这里不是很准确,以后会做说明)。
    3. 泛型是为了解决某些容器、算法等代码的通用性而引入,并且能在编译期间做类型检查。
    4. 泛型利用的是 Object 是所有类的祖先类,并且父类的引用可以指向子类对象的特定而工作。
    5. 泛型是一种编译期间的机制,即 MyArrayList 和 MyArrayList 在运行期间是一个类型。
    6. 泛型是 java 中的一种合法语法,标志就是尖括号 <>


    包装类

    Object 引用可以指向任意类型的对象,但有例外出现了,8 种基本数据类型不是对象,那岂不是刚才的泛型机制要
    失效了?

    实际上也确实如此,为了解决这个问题,java 引入了一类特殊的类,即这 8 种基本数据类型的包装类,在使用过程
    中,会将类似 int 这样的值包装到一个对象中去。

    基本数据类型和包装类直接的对应关系

    基本就是类型的首字母大写,除了 Integer 和 Character

    包装类存在的意义

    当我们需要将某种类型的数据转换成其它的数据类型时,需要通过某种来达到目的。
    而包装类就是这些功能的集大成者,包含多种类型转换方法和其他功能。


    实战(讲一个字符串类型转换成整形数据)


    装箱 / 装包 和 拆箱 / 拆包

    装箱 / 装包 :就是把简单类型数据 变为 包装类类型数据
    拆箱 / 拆包 : 就是把包装类类型数据 变为 简单类型数据

    面试题


    ArrayList 与 顺序表

    铺垫

    1. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
    2. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
    3. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的(序列化:把一个对象转换成字符串)
    4. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者
    CopyOnWriteArrayList
    5. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表 


    在使用任何一个 idea编译器写好的类的时候,一定要先去看一下这个类的构造方法


    ArrayList的三种打印方式


    迭代器打印


    ArrayList基础功能演示

    add 和 addAll ,添加元素功能

    1. public class TestDemo {
    2. public static void main(String[] args) {
    3. ArrayList<String> list = new ArrayList<>();
    4. list.add("a");
    5. list.add("b");
    6. list.add("c");// 添加List元素
    7. System.out.println(list);
    8. System.out.println("===============");
    9. list.add(1,"g");// 在List指定位置中添加元素
    10. System.out.println(list);
    11. System.out.println("========");
    12. List<String> list1 = new ArrayList<>();
    13. list1.add("x");
    14. list1.add("y");
    15. list.addAll(list1);// 将一个list1 整体添加 list中
    16. System.out.println(list);
    17. }
    18. }

    remove - 删除 

    1、指定下标的元素,返回值为删除元素

    内部实现


    2、输出从左往右 第一个指定数据 - 返回值为布尔类型

    内部实现

    get - 获取

    获取指定下标位置的元素

    内部实现

    set - 赋值

    - 将指定下标元素设置为指定数据(可以理解为更新指定下标元素)

    - 返回值为旧元素

    内部实现

    clear - 清空

    - 清空顺序表中的元素

    - 无返回值

    内部实现

    contains - 判断 

    - 判断 指定数据 是否在线性表中

    - 返回值为布尔类型

    内部实现

    indexOf  

    - 返回指定数据在线性表中第一次出现的位置,所对应的下标

    内部实现

    lastIndexOf 

    - 返回 在线性表中,最后一个 与指定元素相等 的 元素下标

    内部实现

    subList - 截取部分

    - 截取部分线性表数据 - 返回值 为 List < E > 类型

    内部实现

    ArrayList的扩容机制

    来看一下,下面的代码是否存在缺陷

    1. public static void main(String[] args) {
    2. List<Integer> list = new ArrayList<>();
    3. for (int i = 0; i < 100; i++) {
    4. list.add(i);
    5. }
    6. }

    首先我们认为这个代码是没有缺陷的,但是因为ArrayList 底层的数组是有一定大小的,那么存放数组的过程中,一定会涉及到扩容,

    前面我们讲到ArrayList 有三种方法,现在使用的是不带参数的,也就是说ArrayList 底层的数组初始容量为零。 那么第一个问题就出现了: 既然数组的容量是为零,那么它怎么还可以存入数据?

    第二个问题: 假设数组初始化容量为10,超过了10,就需要扩容。而且扩容操作时在代码底层执行,是看不见的,也就是说ArrayList在存储数据,隐式的进行扩容操作,那么它的扩容机制是怎样的?

    模拟实现 ArrayList

    新建一个 MyArrayList 类


    构造方法:带参 和 不带参的 两个构造方法

    先来看不带参的

    带参的构造方法

    实现它的基础功能

    add 功能

    add index 

    add 两种用法的效果图

    remove 功能 - 删除删除遇到的第一个 指定元素

    remove 功能 - 删除 index 位置元素

    get - 获取指定下标位置元素

    set - 将指定的下标的元素,置换为 指定的数据

    clear - 清空

    contains - 判断 指定元素 是否在线性表中

    indexOf 和 lastIndexOf ,直接搬原码(注意indexOf 是前面写了的(只要把private改成public就行),直接搬lastIndexOf)

    总结:

    基本功能都实现了,除了subList 没有实现,到后面写到。
    另外 你有没有发现。其实你想要模拟顺序表的功能实现,最好的老师就是原码。以后大家在学习某一个数据结构时,先看它的原码,它会帮助你理解并掌握。

    ArrayList 实践案例 - 扑克牌

    目的:
            1.构造一副扑克牌

            2.洗牌
            3.揭牌

    扑克牌的特点:

            1.点数(13点)
            2.花色(四种花色)

    注意:我们这副扑克,不包含大小王。

    发牌 / 揭牌

    1. import java.util.ArrayList;
    2. import java.util.List;
    3. import java.util.Random;
    4. class Card{
    5. private int point;
    6. private String flowerColor;
    7. public Card(int point, String flowerColor) {
    8. this.point = point;
    9. this.flowerColor = flowerColor;
    10. }
    11. public int getPoint() {
    12. return point;
    13. }
    14. public void setPoint(int point) {
    15. this.point = point;
    16. }
    17. public String getFlowerColor() {
    18. return flowerColor;
    19. }
    20. public void setFlowerColor(String flowerColor) {
    21. this.flowerColor = flowerColor;
    22. }
    23. @Override
    24. public String toString() {
    25. return "{ " +flowerColor +" "+point+" }";
    26. }
    27. }
    28. public class PlayingCard {
    29. // 定义 扑克牌的花色
    30. private static final String[] flowerColors = {"♥","♠","♦","♣"};
    31. // 创建一副扑克
    32. public static List<Card> newCard() {
    33. ArrayList<Card> cards = new ArrayList<>();
    34. for (int i = 0; i < 4; i++) {// 4种花色
    35. for (int j = 1; j <= 13; j++) {// 尖 到 k 一共13个点数
    36. cards.add(new Card(j,flowerColors[i]));
    37. }
    38. }
    39. return cards;
    40. }
    41. // 洗牌
    42. public static void shuffle(List<Card> list){
    43. // 牌数是52,数组下标就是51
    44. // 从最后一张牌开始,随机与 本身 或者 本身前面的任意一张牌 交换位置。
    45. // 这样的做交换性 比 从开头洗 的 打乱顺序的 效率 高。
    46. for (int i = list.size()-1; i >0 ; i--) {
    47. // Random 是一个生成随机数的类
    48. Random random = new Random();
    49. // 通过 Random的引用 random 去调用 nextInt() 方法。
    50. // random.nextInt() 方法,根据括号中的值,随机生成 0 ~ 括号中的值
    51. int rand = random.nextInt(i);
    52. // 将 第 i 张牌 , 与 自身 或者 自身前面的任意一张牌的下标 丢给 swap方法
    53. // 让它去交换位置
    54. swap(list,i,rand);
    55. }
    56. }
    57. // 交互式洗牌模式
    58. private static void swap(List<Card> list,int i,int j){
    59. // 我们现在是面向对象,ArrayList虽然底层是一个数组,但是需要使用方法,才能操作数组的元素
    60. // 并不能像数组一样,直接操作
    61. // Card tmp = list[i];
    62. Card tmp = list.get(i);// 获取 顺序表中,对应下标的元素
    63. // list[i] = list[j];
    64. list.set(i,list.get(j));// 将 j下标的元素,赋给 i 下标的元素,
    65. // list[j] = tmp;
    66. list.set(j,tmp);
    67. }
    68. public static void main(String[] args) {
    69. System.out.println("======一副买来拆的牌==========");
    70. List<Card> list = newCard();
    71. System.out.println(list);
    72. System.out.println("======== 洗牌 =========");
    73. shuffle(list);
    74. System.out.println(list);
    75. System.out.println("======== 发牌,3个人轮着发,每个人5张牌=========");
    76. ArrayList<ArrayList<Card>> player = new ArrayList<>();
    77. // 这行代码 就是 一个二维数组,
    78. // 首先我们有一个player, player 的每个元素 都是 ArrayList<Card> 类型。
    79. // 也就是说每个元素就是一个顺序表,也可以说是一个一维数组。
    80. // 你也可以这么理解 第一个 ArrayList 是用来记录有 玩家的方位/顺序表的地址/数组的地址
    81. // 第二个ArrayList 就是 每个玩家手上牌的情况/数组的元素情况/顺序表的底层数组元素情况。
    82. // 你可以 把 player 看作牌桌,等待三位玩家的入场。
    83. // 打牌三人组
    84. ArrayList<Card> playerOne = new ArrayList<>();
    85. ArrayList<Card> playerTwo = new ArrayList<>();
    86. ArrayList<Card> playerThree = new ArrayList<>();
    87. // 将三位玩家的信息,加载到 player 当中
    88. player.add(playerOne);
    89. player.add(playerTwo);
    90. player.add(playerThree);
    91. for (int i = 0; i < 5; i++) {//5 轮牌
    92. for (int j = 0; j < 3; j++) {// 每个人 轮着发,最终每个人5张牌
    93. Card card = list.remove(0);
    94. player.get(j).add(card);
    95. }
    96. }
    97. // 打印每个人的手牌
    98. System.out.println("playerOne的手牌:"+ playerOne);
    99. System.out.println("playerTwo的手牌:"+playerTwo);
    100. System.out.println("playerThree的手牌:"+playerThree);
    101. System.out.println("list 剩余的牌:"+list);
    102. }
    103. // public static void main1(String[] args) {
    104. // Card card = new Card(3,"♠");
    105. // System.out.println(card);
    106. // }
    107. }

  • 相关阅读:
    058:mapboxGL监听键盘事件,通过panBy控制前后左右移动
    flutter 递归
    Golang context包的源码分析
    go 语言爬虫库goQuery 的详细使用(知乎日报详情页解析示例)
    DALL E2【论文阅读】
    【高速数字化仪应用案例系列】虹科数字化仪在通信领域的应用
    MySQL之InnoDB浅析
    数据结构(3.9_1)——特殊矩阵的压缩存储
    halcon模板匹配捆绑测量矩形检测芯片针脚
    C#,文字排版的折行问题(Word-wrap problem)的算法与源代码
  • 原文地址:https://blog.csdn.net/m0_65601072/article/details/134166948