Day09 数组

Java Array

一. 数组的定义

  • 数组是相同类型数据的有序集合。
  • 数组是由相同类型的若干个数据,按照一定的先后次序排列而成。
  • 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个对应的下标来访问它们.

二. 数组的声明与创建

  • 必须先声明数组变量,才能在程序中使用数组。语法如下:

    dataType[] arrayName;  //应该使用的方法
    dataType arrayName[];  //C/C++式声明,效果相同,不建议使用
    
  • Java使用new操作符来创建数组,语法如下:

    dataType[] arrayName = new dataType[arraySize];
    //声明和创建可以放在一起,实例
    int[] nums = new int[10];
    //创建了一个长度为10的int型数组
    
  • 数组的元素是通过下标访问的。数组下标从0开始。

  • 使用arrayName.length可以获取数组长度。

三. 数组的三种初始化

  • 静态初始化:

    //静态初始化的例子
    int[] a = {1,2,3};
    Man[] mans = {new man(1,1), new man(2,2)}; //对象数组
    
  • 动态初始化:(包含了默认初始化)

    int[] a = new int[2];
    a[0] = 1;
    a[1] = 2;
    
  • 数组的默认初始化:

    数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。

四. 数组的四个基本特点

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

五. 数组边界

  • 数组下标的合法区间:[0, length-1],如果越界就会报错,如下例子就会报一个数组越界的错误:

    public class ArrayLearn {
        public static void main(String[] args) {
            int[ ] a = new int[2];
            System.out.println(a[2]);
        }
    }
    //报错,数组下表越界
    //Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
    

六. 数组的使用

  • 循环遍历数组:

    public class ArrayLearn {
        public static void main(String[] args) {
            int[ ] a = new int[5]; //使用了的默认的初始化值0
    
            //普通的for循环
            for (int i = 0; i < a.length; i++) {
                System.out.println(a[i]);
            }
            
            //增强for循环
            //Use arrayName.for can create for loop for array
            for (int i : a) {
                System.out.println(i);
            }
        }
    }
    
  • 数组作为方法的参数和返回值:

    public class ArrayLearn {
        public static void main(String[] args) {
            int[] arrays = {1,2,3,4,5};
            showArray(reverse(arrays));
    
        }
    
        public static void showArray(int[] arrays) {
            for (int array : arrays) {
                System.out.printf(array + " ");
            }
        }
    
        public static int[] reverse(int[] arrays) {
            int[] res = new int[arrays.length];
            for (int i = 0; i < arrays.length; i++) {
                res[arrays.length-i-1] = arrays[i];
            }
            return res;
        }
    }
    

六. 多维数组

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

  • 一个二维数组的例子:

    int arr[][] = new int[2][5];
    //可以看作一个两行五列的数组
    int a = arr[0][0];
    //取得arr的第一个元素arr[0]的第一个元素(arr[0])[0]
    //此时arr[0]也是一个数组,即数组套数组就是多维数组
    

七. Arrays类

  • Arrays类是数组的工具类 java.util.Arrays

  • 由于数组对象本身并没有什么方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作。

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

  • 它具有以下常用功能:

    • 给数组赋值:通过fill方法。

    • 对数组排序:通过sort方法,按升序。

    • 比较数组:通过equals 方法比较数组中元素值是否相等。

    • 查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作

      下面是一些例子,想要详细的了解可以自己翻阅JDK帮助文档了解更多的方法。

    import java.util.Arrays;
    
    public class ClassArrays {
        public static void main(String[] args) {
            //Arrays
            int[] a = {1,7,2,5,4,3,0,10};
    
            //toString(),打印数组
            System.out.println(Arrays.toString(a));
    
            System.out.println("=============================");
            //fill( , ), 填充数组
            //fill( , , , ) 填充数组对应下标区间的
            int[] b = new int[10];
            Arrays.fill(b, 3, 7, 5);
            System.out.println(Arrays.toString(b));;
    
            System.out.println("=============================");
            //排序
            Arrays.sort(a);
            System.out.println(Arrays.toString(a));
    
        }
    }
    
    

八. 稀疏数组

  • 在数组大部分元素无意义时,我们可以使用稀疏数组来压缩数组来节省空间。

  • 稀疏数组的处理方式是:

    • 首元素记录数组有几行几列,一共有多少个值。
    • 接下来的元素储存有意义值的所在位置和其值,也是使用数组进行储存。
  • 下面是一个稀疏数组的例子:


				1 0 0 0 0 0                  //一个大概的稀疏矩阵
				0 0 0 1 0 0                  //只做例子
				1 1 0 0 0 0                    
				0 0 0 0 0 0 

该数组的稀疏数组表示如下表:

[0] 4 6 4
[1] 0 0 1
[2] 1 3 1
[3] 2 0 1
[4] 2 1 1
  • 一个实例程序:
public class SparseMatrix {
    public static void main(String[] args) {
        //创建的稀疏矩阵
        System.out.println("==========================================");
        System.out.println("给出的稀疏矩阵为:");
        int[][] box = new int[11][11];
        box[1][2] = 1;
        box[2][3] = 2;
        printArray(box);

        System.out.println("==========================================");
        //创建一个稀疏数组存储稀疏矩阵
        System.out.println("对应的稀疏数组为:");
        int[][] spareArray = createSpareArray(box);
        printArray(spareArray);

        System.out.println("==========================================");
        //创建一个数组接收转换完成的稀疏数组
        System.out.println("还原后的稀疏矩阵");
        int[][] back = returnBack(spareArray);
        printArray(back);


    }

    /**
     * 用于取得稀疏矩阵中有效数字的个数
     * @param arr 传入的存储稀疏矩阵的数组
     * @return 稀疏矩阵中有效元素的个数
     */
    public static int getSignificantFiguresNumber(int[][] arr) {
        int num = 0; //记录有效数字的个数
        for (int[] ints: arr) {  //遍历二维数组,找到不为0的元素
            for (int x : ints ) {
                if (0 != x ) ++num;  //计数器+1
            }
        }
        return num;
    }

    /**
     * 创建稀疏数组
     * @param arr 传入的存储稀疏矩阵的数组
     * @return 转换完成的稀疏数组
     */
    public static int[][] createSpareArray(int[][] arr) {

        int counts = getSignificantFiguresNumber(arr); //得到有效数字的个数
        int[][] res = new int[++counts][3];  //创建稀疏数组

        int k = 1; //稀疏数组的下标,由于首元素储存全局信息,所以从1开始
        for (int i = 0; i < arr.length; i++) {  //遍历稀疏矩阵
            for (int j = 0; j < arr[0].length; j++) {
                if (0 != arr[i][j]) {  //元素不为零
                    res[k][0] = i;  //储存有效元素的行列信息
                    res[k][1] = j;
                    res[k][2] = arr[i][j];  //储存有效数字
                    ++k; //下标迭代
                }
            }
        }
        //储存全局信息
        res[0][0] = arr.length;
        res[0][1] = arr[0].length;
        res[0][2] = counts;

        return res;
    }

    /**
     * 打印传入的二维数组
     * @param arr 需要打印的二维数组
     */
    public static void printArray(int[][] arr) {
        for (int[] ints: arr) {
            for (int x : ints ) {
                System.out.printf(x + "\t");
            }
            System.out.println();
        }
    }

    /**
     * 还原稀疏矩阵
     * @param arr 需要还原的稀疏数组
     * @return 还原后储存稀疏矩阵的数组
     */
    public static int[][] returnBack(int[][] arr) {
        //根据稀疏矩阵的全局信息创建对应的数组储存稀疏矩阵
        int[][] res = new int[arr[0][0]][arr[0][1]]; 
        //遍历稀疏数组
        for (int i = 1; i < arr.length; i++) {
            //将对应位置的元素还原
            res[arr[i][0]][arr[i][1]] = arr[i][2]; 
        }
        return res; 
    }
}

九. 冒泡排序

  • 最基本的排序算法,两层循环,外层冒泡轮数,里层一次比较。由于是两层嵌套循环,他的时间复杂度为O(n^2)。以下是一个使用冒泡排序对数组进行排序的实例:
import java.util.Arrays;

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = {1, 4, 2, 5, 7, 2, 8};
        bubbleSort(arr); //使用冒泡排序对数组进行排序
        System.out.println("Array After Bubble Sort: " + Arrays.toString(arr));//输出排序后的数组

    }

    //排序过程
    //1 4 2 5 7 2 8
    //1 2 4 5 2 7 8      (1) flag == true
    //1 2 4 2 5 7 8      (2) flag == true
    //1 2 2 4 5 7 8      (3) flag == true
    //1 2 2 4 5 7 8      (4) flag == false

    /**
     * 冒泡排序,使用flag标签判断数组是否还需要排序,默认为false,即数组不需要再次排序,
     * 如果在一次遍历中改变了元素的位置,即认为该数组仍然需要排序,将flag置为true。使用
     * 这样的方法可以减少排序中数组有序时无用的循环遍历。
     * 该算法的冒泡排序为从从小到大排序
     * @param arr 待排序的数组,传递的为引用值
     */
    public static void bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            boolean flag = false; //默认该次循环结束后不需要继续进行排序
            for (int j = 0; j < arr.length-1; j++) {
                if (arr[j] > arr[j+1]) {
                    int tmp = arr[j]; //交换元素位置
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                    flag = true;  //更改标记flag
                }
            }
            System.out.println(i+1 + ": " + Arrays.toString(arr));//输出每一次排序的结果
            if (!flag) break;
        }
    }
}

拓展

  • 数组的内存分析:

    一个简单的分析理解:数组就是一个对象,声明数组时产生了一个引用变量,存储在栈中,当你使用new操作符新建了一个数组对象并赋值给你的声明时,你的引用类型指向堆中新建的数组对象,

  • 使用new关键字新建的对象都是保存在堆中的

posted @ 2021-02-23 11:31  心叶酱  阅读(52)  评论(0编辑  收藏  举报