Java 的数组详解

数组的定义

  • 数组是相同类型数据的有序集合

  • 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成

  • 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标(编号、标记)来访问它,下标是从 0 开始的,如果是存 10 个数组,那么下标是从 0 ~ 9

  • 代码举例

    public class ArrayDemo01 {
        //变量的类型 变量的名字   =   变量的值
        public static void main(String[] args) {
            int[] nums = {1,2,3,4,5,6,7,8,9,10};
            System.out.println(nums[0]);    //1 打印下标元素为0的内容
        }
    }
    

数组的声明创建

  • 首先必须声明数组变量,才能在程序中使用数组

    • 语法

      dataType[] arrayRefVar;	//首选的方法
      dataTypr arrayRefVar[];	//效果相同,但不建议
      
    • 代码举例

      //数组类型[] 数组名字;
      int[] nums;
      int nums[];
      
  • Java 语言使用 new 操作符来创建数组

    • 语法

      dataType[] arrayRefVar = new dataType[srraySise];
      
    • 代码举例

      //数组类型[] 数组名字 = new 数组类型[数组容量];
      int[] nums = new int[10]
      
  • 数组的元素是通过索引访问的,数组索引0 开始

  • 获取数组长度

    //数组名字.length
    arrays.length	//nums.length
    
  • 代码总结举例

    public class ArrayDemo01 {
        //变量的类型 变量的名字   =   变量的值
        public static void main(String[] args) {
            //int[] nums = {1,2,3,4,5,6,7,8,9,10};  //一次性给数组元素赋值
            //System.out.println(nums[0]);    //1
            //2种定义数组方法
            int[] nums; //首选定义方法
            int nums2[]; //第二种定义方法  C语言语法,为了让C语言程序员而兼容。
    
            //int[] nums = new int[10]; //一步到位定义好存放数组大小
            nums = new int[10]; //这里面可以存放 10 个 int 类型的数字
    
            //依次给数组元素赋值
            nums[0] = 1;
            nums[1] = 2;
            nums[2] = 3;
            nums[3] = 4;
            nums[4] = 5;
            nums[5] = 6;
            nums[6] = 7;
            nums[7] = 8;
            nums[8] = 9;
            nums[9] = 10;
    
            //计算所有元素的和
            int sum = 0;
            //获取数组长度:arrays.length
    
            for (int i = 0; i < nums.length; i++) {
                sum = sum + nums[i];
            }
    
            System.out.println("总和为:" + sum);   //55
        }
    }
    

数组的内存

  • 数组内存分析

  • 画图分析数组内存

数组的三种初始化

  1. 静态初始化创建的同时赋值

    • 代码语法举例

      int[] a = {1, 2, 3};	//正常的静态初始化
      Man[] mans = {new Man(1, 1), new Man(2, 2)};	//引入的静态初始化
      
  2. 动态初始化:包含默认初始化,未赋值的元素默认为 0

    • 代码语法举例

      int[] a = new int[3];
      a[0] = 1;	
      a[1] = 2;
      System.out.println(a[0]);	//1
      System.out.println(a[1]);	//2
      System.out.println(a[3]);	//0		未赋值则为 0		默认初始化
      
  3. 数组的默认初始化:数组是引用类型,它的元素相当于实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化(0)

    • 代码语法举例

      int[] a = new int[1];
      System.out.println(a[1]);	//0		未赋值则为 0
      

数组的四个基本特点

  1. 其长度是确定的。数组一旦被创建,它的大小就是不可以改变
  2. 元素必须是相同类型不允许出现混合类型
  3. 数组中的元素可以是任何数据类型,包括基本类型引用类型
  4. 数组变量属于引用类型,数组也可以看成是对象,数组指定每个元素相当于该对象成员变量数组本身就是对象Java对象是在中的,因此数组无论保护原始类型还是其他对象类型数组对象本身是在堆中的

数组的边界

  • 下标的合法区间[0, length-1],如果越界就会报错 ArrayIndexOutOfBoundsException (数组下标越界异常)

    • 代码举例

      public class ArrayDemo02 {
          public static void main(String[] args) {
              //静态初始化:创建的同时赋值
              int[] a = {1, 2, 3, 4, 5, 6, 7, 8};
              for (int i = 0; i < a.length; i++) {
                  System.out.println(a[i]);
                  //正常遍历出 a 这个数组内所有值
              }
              /*
                  for (int i = 0; i <= a.length; i++) {   //将 i < a.length 改为 i <= a.length
                      System.out.println(a[i]);
                      //先报错随后正常遍历出a这个数组内所有值
                      //下标为 数组长度 -1,例如 a[0] = 1 而不是 a[1] = 1。当 for 循环走到 i <= a.length 时,下标为 8 (a[8]),a(8)未赋值且超过数组最大长度因此会越界报错
                  }
               */
          }
      }
      
  • 结论

    • 数组是相同数据类型 (数据类型可以为任意类型)有序集合
    • 数组也是对象数组元素相当于对象成员变量
    • 数组长度是确定不可改变的越界报错 ArrayIndexOutOfBoundsException (数组下标越界异常)

数组的使用

  • 普通的 For 循环

    public class ArrayDemo03 {
        public static void main(String[] args) {
            int[] arrays = {1, 2, 3, 4, 5};
    
            //打印全部的数组元素
            for (int i = 0; i < arrays.length; i++) {
                System.out.println(arrays[i]);
            }
    
            //计算所有元素的和
            int sum = 0;
            for (int i = 0; i < arrays.length; i++) {
                sum += arrays[i];   //sum = sum + arrays[i]
            }
            System.out.println("sum=" + sum);
    
            //查找最大元素
            int max = arrays[0];
            for (int i = 1; i < arrays.length; i++) {   //arrays[0] 已经是 max 的默认值,因此我们改成 i = 1 ,从 1 开始
                if (arrays[i] > max){
                    max = arrays[i];
                }
            }
            System.out.println("max=" + max);
        }
    }
    
  • For-Each 循环

    public class ArrayDemo04 {
        public static void main(String[] args) {
            int[] arrays = {1, 2, 3, 4, 5};
            //JDK1.5特性  只遍历全部值,没有下标
            for (int array : arrays) {  //增强型 for 循环,关键字 arrays.for 自动生成
                System.out.println(array);
            }
        }
    }
    
  • 数组作方法入参

    public class ArrayDemo04 {
        public static void main(String[] args) {
            int[] arrays = {1, 2, 3, 4, 5};
            //调用打印数组元素方法
            printArray(arrays); //更好的遍历数组,在需要时可以取到下标
        }
        //打印数组元素
        public static void printArray(int[] arrays){    //更好的遍历数组,在需要时可以取到下标
            for (int i = 0; i < arrays.length; i++) {
                System.out.print(arrays[i] + " ");
            }
        }
    }
    
  • 数组作返回值

    public class ArrayDemo04 {
        public static void main(String[] args) {
            int[] arrays = {1, 2, 3, 4, 5};
            int[] result = reverse(arrays);	//调用反转数组方法
            printArray(result); //更好的遍历数组,在需要时可以取到下标
        }
    
        //打印数组元素
        public static void printArray(int[] arrays){    //更好的遍历数组,在需要时可以取到下标
            for (int i = 0; i < arrays.length; i++) {
                System.out.print(arrays[i] + " ");
            }
        }
    
        //反转数组
        public static int[] reverse(int[] arrays){
            int[] result = new int[arrays.length];  //保证传入的数组不会超出最大长度
    
            //反转的操作
            for (int i = 0, j = result.length-1; i < arrays.length; i++, j--) { //result.length-1 是因为下标从 0 开始而 length 长度是从 1 开始,一次使用两个组合 for 循环
                result[j] = arrays[i];
            }
    
            return result;	//返回值
        }
    }
    

多维数组

  • 多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一堆数组,其每一个元素都是一个一堆数组

    • 二维数组

      • 语法

        int a[][] = new int[2][5];
        int[][] a = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
        
      • 代码举例

        public class ArrayDemo05 {
            public static void main(String[] args) {
                int[][] array = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
                //int array[][] = new int[2][5];    //相当于一个数组内嵌套了 2 层的数组
                /*
                    //解析如下:
                    a =
                    {
                        {1, 2}, //2 层嵌套的数组
                        {3, 4},
                        {5, 6},
                        {7, 8},
                        {9, 10},
                    }
                */
                //打印指定元素的值
                System.out.println(array[0][0]);    //1
                System.out.println(array[0][1]);    //2
                System.out.println(array[1][1]);    //4
                System.out.println(array.length);   //5 5列
                System.out.println(array[0].length);    //2 2行
            }
        }
        
      • 解析:以上二维数组 a 可以看成一个两行五列数组

    • 三维数组

      • 语法

        int a[][][] = new int[][][];
        int[][][] a = {{{1, 2}, {3, 4}}};
        
      • 代码举例

        public class ArrayDemo05 {
            public static void main(String[] args) {
                int[][][] array = {{{1, 2}, {3, 4}},{{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}};
                //int array[][][] = new int[2][2][3];    //相当于一个数组内嵌套了 3 层的数组
                /*
                    //解析如下:
                    a =
                    {
                    	{
                    		{1, 2},
                    		{3, 4},
                    	},
                    	{
                    		{5, 6},
                    		{7, 8},
                    	},
                    	{
                    		{9, 10},
                    		{11, 12},
                    	},
                        //3 层嵌套的数组
                    }
                */
                //打印指定元素的值
                System.out.println(array[0][0][0]);    //1
                System.out.println(array[0][0][1]);    //2
                System.out.println(array[1][1][1]);    //8
                System.out.println(array.length);   //3 3组
                System.out.println(array[0].length);    //2 2列
                System.out.println(array[0][1].length); //2 2行
            }
        }
        
      • 解析:以上三维数组 a 可以看成一个两行两列三组数组

    • ...

  • 遍历多维数组

    • 遍历二维数组代码举例

      public class ArrayDemo05 {
          public static void main(String[] args) {
              int[][] array = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
              //遍历
              for (int i = 0; i < array.length; i++) {
                  for (int j = 0; j < array[i].length; j++) {
                      System.out.println(array[i][j]);
                  }
              }
          }
      }
      
    • 遍历三维数组代码举例

      public class ArrayDemo06 {
          public static void main(String[] args) {
              int[][][] array = {{{1, 2}, {3, 4}},{{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}};
              //遍历
              for (int i = 0; i < array.length; i++) {
                  for (int j = 0; j < array[i].length; j++) {
                      for (int k = 0; k < array[i][j].length; k++) {
                          System.out.println(array[i][j][k]);
                      }
                  }
              }
          }
      }
      
    • ...

数组的 Arrays 类

  • 调用数组的工具类 java.util.Arrays

    import java.util.Arrays;	//调用工具类
    
    public class ArraysDemo07 {
        public static void main(String[] args) {
            int[] a = {1,2,3,4,3554,65,6,231324};
    
            Arrays.sort(a);//所有的 Arrays 都需要调用 import java.util.Arrays; 工具类
    }
    
  • 由于数组对象并没有什么方法可以供我们调用,但 API 中提供了一个工具类 Arrays 供我们使用,从而可以对数据对象进行一些基础操作

    • 查看 Arrays 类内所有方法

      • 方法①:打开 JDK 帮助文档(搜索 Arrays)查看

      • 方法②:直接使用 IDEA 查看源代码

        1. 创建 main 方法后键入"Arrays"如下图,点击即可调用它的工具类

        2. 鼠标停放在调用的工具类 java.util.ArraysArrays 关键字几秒会弹出一个窗口,以下操作后点击 跳转到源 可以索引到方法源

        3. 进入 Arrays 源代码内后下方可以看到 Arrays 点击它即可自行查看 Arrays 内所有的源方法以及使用方法

  • Arrays 类中的方法都是 static 修饰的静态方法,在使用的时候可以直接使用类名进行调用,而“不用”使用对象来调用(注意:是“不用”而不是“不能”)

    import java.util.Arrays;
    
    public class ArraysDemo07 {
        public static void main(String[] args) {
            int[] a = {1,2,3,4,3554,65,6,231324};
            
            //直接调用
            printArray(a);  //[1, 2, 3, 4, 3554, 65, 6, 231324]
        }
        
        //创建方法	使用 static 修饰符
        public static void printArray(int[] a){
            System.out.print("[");
            for (int i = 0; i < a.length; i++) {
                String symbol = "";
                if (i != a.length-1){
                    symbol = ", ";
                }else{
                    symbol = "";
                }
                System.out.print(a[i] + symbol);
            }
            System.out.println("]");
        }
    }
    
  • 它具有以下常用功能:

    • 打印数组元素:通过 toString 方法直接遍历

      import java.util.Arrays;
      
      public class ArraysDemo07 {
          public static void main(String[] args) {
              int[] a = {1,2,3,4,3554,65,6,231324};
      
              //打印数组元素:Arrays.tostring
              System.out.println(Arrays.toString(a)); //[1, 2, 3, 4, 3554, 65, 6, 231324]
              
              //了解原理后咱们也可以自己创建方法来实现
              //可以但不建议,大家了解一下就好。不建议重复造轮子!
              printArray(a);  //[1, 2, 3, 4, 3554, 65, 6, 231324]
          }
          
          //创建方法
          public static void printArray(int[] a){
              System.out.print("[");
              for (int i = 0; i < a.length; i++) {
                  String symbol = "";
                  if (i != a.length-1){
                      symbol = ", ";
                  }else{
                      symbol = "";
                  }
                  System.out.print(a[i] + symbol);
              }
              System.out.println("]");
          }
      }
      
    • 给数组重新赋值:通过 fill 方法重新填充

      import java.util.Arrays;
      
      public class ArraysDemo07 {
          public static void main(String[] args) {
              int[] a = {1,2,3,4,3554,65,6,231324};
      
              //数组填充(重新赋值)
              //Arrays.fill(a, 0);  //全部重新赋值为 0
              //System.out.println(Arrays.toString(a)); //[0, 0, 0, 0, 0, 0, 0, 0]
              Arrays.fill(a, 2, 4, 0);    //包括下标为 2 但不包括下标为 4 之间的元素重新赋值为 0
              System.out.println(Arrays.toString(a)); //[1, 2, 0, 0, 3554, 65, 6, 231324]
          }
      }
      
    • 对数组排序:通过 sort 方法,按升序排序

      import java.util.Arrays;
      
      public class ArraysDemo07 {
          public static void main(String[] args) {
              int[] a = {1,2,3,4,3554,65,6,231324};
      
              Arrays.sort(a);//数组进行排序:升序
              System.out.println(Arrays.toString(a)); //[1, 2, 3, 4, 6, 65, 3554, 231324]
          }
      }
      
    • 比较数组:通过 equals 方法比较数组中元素值是否相等

      import java.util.Arrays;
      
      public class ArraysDemo07 {
          public static void main(String[] args) {
              int[] a = {1,2,3,4,3554,65,6,231324};
      
              //给数组中的元素值比较是否相等
              int[] b = {0};
              if(Arrays.equals(a, b)) {   //不相等
                  System.out.println("相等");
              }else{
                  System.out.println("不相等");
              }
              int[] c = {1,2,3,4,3554,65,6,231324};
              if(Arrays.equals(a, c)) {   //相等
                  System.out.println("相等");
              }else{
                  System.out.println("不相等");
              }
          }
      }
      
    • 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作

      import java.util.Arrays;
      
      public class ArraysDemo07 {
          public static void main(String[] args) {
              int[] a = {1,2,3,4,3554,65,6,231324};
      
              //对数组进行二分查找法操作
              Arrays.sort(a); //使用二分查找法的数组必须是有序的
              System.out.println(Arrays.binarySearch(a, 0));  //2     查找元素值 3,找到后返回下标。
              /*
                   若未找到元素值则会出现以下情况:
                   [1] 搜索值不是数组元素值,大小在所有数组范围内,下标从1开始计数,返回“ - 按顺序插入点的下标”
                   [2] 搜索值是数组元素值,下标从0开始计数,返回搜索值的下标
                   [3] 搜索值不是数组元素值,且大于数组内所有元素值,返回 – (数组最大长度 + 1)
                   [4] 搜索值不是数组元素值,且小于数组内所有元素值,返回 – 1
               */
          }
      }
      
    • ...

数组的冒泡排序

  • 冒泡排序无疑是最为出名的排序算法之一 (总共有八大排序)

    • 冒泡排序的步骤 (两两比较)

      1. 比较数组中,两个相邻的元素,如果第一个数比第二个数,我们就将它们交换位置

      2. 每一次比较,都会产生出一个最大或者最小的数字

      3. 下一轮则可以少一次排序

      4. 依次循环,直到结束

    • 代码举例

      import java.util.Arrays;
      
      public class ArrayDemo08 {
          public static void main(String[] args) {
              int[] a = {2,4,2,1,3,5,6,66,77,7,4,0};
              int[] sort = sort(a);   //调用完我们创建的排序方法后返回一个排序后的数组
              System.out.println(Arrays.toString(sort));
          }
      	
          //冒泡排序方法
          public static int[] sort(int[] array){
              //临时变量
              int temp = 0;
      
              //外层循环:判断我们这个要走多少次
              for (int i = 0; i < array.length-1; i++) {  //当循环走到最后的下标时无法与下个下标进行比较就会溢出,因此这里需要 array.length-1 预留一个位置进行比较排序
                  //内层循环:比较判断两个数,如果第一个数比第二个数大,则交换位置
                  for (int j = 0; j < array.length-1-i; j++) {    //每次遍历比较都要排除掉i且给最后下标的元素值预留1个位置,因此需要 array.length-1-i
                      if (array[j+1]<array[j]){   //判断比较数组的下个下标的数是否大于目前下标的数
                          temp = array[j];    //将本次对比的元素值存进临时变量
                          array[j] = array[j+1];
                          array[j+1] = temp;
                      }
                  }
              }
      
              return array;   //排序完成后返回数组
      
          }
      }
      
  • 冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较,江湖中人尽皆知

  • 我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为 O(n2)

  • 优化代码举例

    import java.util.Arrays;
    
    public class ArrayDemo08 {
        public static void main(String[] args) {
            int[] a = {2,4,2,1,3,5,6,66,77,7,4,0};
            int[] sort = sort(a);   //调用完我们创建的排序方法后返回一个排序后的数组
            System.out.println(Arrays.toString(sort));
        }
    
        //冒泡排序方法
        public static int[] sort(int[] array){
            //临时变量
            int temp = 0;
    
            //外层循环:判断我们这个要走多少次
            for (int i = 0; i < array.length-1; i++) {  //当循环走到最后的下标时无法与下个下标进行比较就会溢出,因此这里需要 array.length-1 预留一个位置进行比较排序
                boolean flag = false;   //通过 flag 标识减少没有意义的比较
                //内层循环:比较判断两个数,如果第一个数比第二个数大,则交换位置
                for (int j = 0; j < array.length-1-i; j++) {    //每次遍历比较都要排除掉i且给最后下标的元素值预留1个位置,因此需要 array.length-1-i
                    if (array[j+1]<array[j]){   //判断比较数组的下个下标的数是否大于目前下标的数
                        temp = array[j];    //将本次对比的元素值存进临时变量
                        array[j] = array[j+1];
                        array[j+1] = temp;
                        flag = true;
                    }
                }
                if (flag == false){ //只要未执行以上循环则会终止所有循环继续走下面的代码。节省时间成本
                    break;
                }
            }
    
            return array;   //排序完成后返回数组
    
        }
    }
    

稀疏数组

  • 稀疏数组的介绍

    • 当一个数组中大部分元素为 0,或者为同一数值的数组时,可以使用稀疏数组来保存该数组

    • 稀疏数组的处理方式

      • 记录数组一共有几行几列,有多少个不同值
      • 把具有不同值元素行列以及记录在一个小规模的数组中,从而缩小程序的规模
    • 如下图 (左边是原始数组,右边是稀疏数组)

      • 下标 0稀疏数组记录整个数组有 6 行 7 列 8 个不为 0 的有效值
      • 下标 1~8稀疏数组:记录每个有效值的位置。例如下标 1 中的 22 ,在数组中,下标从 0 开始计数,那么在稀疏数组中记录为 0 3 22,即为在下标为 0 的行,下标为 3 的列,记录值为 22
  • 稀疏数组的应用

    • 要求:编写五子棋游戏中,有存盘退出和续上盘的功能

    • 问题分析:因为该二维数组的很多值是默认值 0,因此记录了很多没有意义的数据

    • 解决方法稀疏数组

      • 代码举例

        public class ArrayDemo09 {
            public static void main(String[] args) {
                //1.创建一个二维数组 11*11(11行11列)      0:没有棋子      1:黑棋        2:白棋
                int[][] array1 = new int[11][11];
                array1[1][2] = 1;   //黑棋位于2行3列(数组从 0 计数)
                array1[2][3] = 2;   //白棋位于3行4列(数字从 0 计数)
                //输出原始的数组
                System.out.println("输出原始的数组");
                for (int[] ints : array1) {
                    for (int anInt : ints) {
                        System.out.print(anInt + "\t");
                    }
                    System.out.println();
                }
                //转换为稀疏数组来保存
                //1. 获取有效值的个数
                int sum = 0;
                for (int i = 0; i < array1.length; i++) {   //array1.length 取二维数组嵌套的数组个数    11行
                    for (int j = 0; j < array1[i].length; j++) {    //array1[0].length 取遍历下标 i 的子数组中值的个数    11列
                        if (array1[i][j] != 0){
                            sum++;
                        }
                    }
                }
                System.out.println("有效值的个数:" + sum);
                //2. 创建一个稀疏数组
                int[][] array2 = new int[sum+1][3]; //之所以行数为有效值个数加 1 是因为需要多加 1 行记录行总数、列总数、有效值个数。固定 3 列
                //多出来的 1 行用用以下代码赋值记录行总数、列总数、有效值个数
                array2[0][0] = 11;
                array2[0][1] = 11;
                array2[0][2] = sum;
                //遍历二维数组,将非零的值(有效值),存放在稀疏数组中
                int count = 0;
                for (int i = 0; i < array1.length; i++) {
                    for (int j = 0; j < array1[i].length; j++) {
                        if (array1[i][j] != 0){
                            count++;    //行递增
                            //利用行递增给稀疏数组赋值记录
                            array2[count][0] = i;
                            array2[count][1] = j;
                            array2[count][2] = array1[i][j];
                        }
                    }
                }
                //3. 输出稀疏数组
                System.out.println("稀疏数组");
                for (int i = 0; i < array2.length; i++) {
                    System.out.println(array2[i][0] + "\t" + array2[i][1] + "\t" + array2[i][2]);
                }
                //数组还原归位
                //1. 读取稀疏数组
                int[][] array3 = new int[array2[0][0]][array2[0][1]];   //根据数组默认初始化,至此一行代码已还原所有 0 值归为
                //2. 给其中的元素还原它的值
                for (int i = 1; i < array2.length; i++) {   //还原过程中,头部记录的综合信息不需要读取,因此 i=1,从下标 1 开始
                    array3[array2[i][0]][array2[i][1]] = array2[i][2];  //在已记录的有效值位置还原有效值
                }
                //3. 打印
                System.out.println("打印还原的数组");
                for (int[] ints : array3) {
                    for (int anInt : ints) {
                        System.out.print(anInt + "\t");
                    }
                    System.out.println();
                }
            }
        }
        
posted @ 2024-03-29 16:59  阿俊学JAVA  阅读(766)  评论(0编辑  收藏  举报