数组

数组概述

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

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

  • 数组里的每一个数据称作一个数组元素, 每个数组元素可以通过一个下标来访问

  • 例如一个球队就是数组, 里面的球员就是数组元素; 例如需要十个数值, 即需要十个变量, 但使用数组即可利用下标访问元素, 无需定义十个变量存放数值


声明数组变量

  • 首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法

    dataType[] arrayRefVar;   // 首选的方法
    double[] myList;         // 首选的方法
    //数据类型[] 数组名  
    或
     
    dataType arrayRefVar[];  // 效果相同,但不是首选方法
    
  • 注意: 建议使用 dataType[] arrayRefVar 的声明风格声明数组变量。 dataType arrayRefVar[] 风格是来自 C/C++ 语言 ,在Java中采用是为了让 C/C++ 程序员能够快速理解java语言


创建数组

  • Java语言使用new操作符来创建数组,语法如下:
arrayRefVar = new dataType[arraySize];

//另外,你还可以使用如下的方式创建数组。
dataType[] arrayRefVar = {value0, value1, ..., valuek};
  • 上面的语法语句做了两件事:

    • 使用 dataType[arraySize] 创建了一个数组(创建一个数组)
    • 把新创建的数组的引用赋值给变量 arrayRefVar(数组变量)
  • 数组的元素是通过索引访问的。数组索引从 0 开始,所以索引值从 0 到 arrayRefVar.length-1(例如需要10个, 则0~9)

  • 获取数组长度(arrrayRefVar.length; 例如需要10个,则length显示10个(现实世界);无需-1哦)


数组代码尝试

package Array;

import java.util.Scanner;

public class Demo_0 {
    //变量类型 变量名字 = 变量值
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("数组长度: ");
        int y = input.nextInt();
        int[] nums;//声明数组定义;未赋值,即未分配空间;首选风格
        //int num[];同上,单纯的C/C++风格而已;不是首选
        nums = new int[y];//创建数组,即存放y个int类型的数值
        //一个叫nums的大盒子放了y个用于int类型的小盒子
        //这里不是说二维数组哦
        //数组下标由0开始哦; 上述情况即存放0号小盒子~9号小盒子

        int c = 0;
        while (c < nums.length) {
            System.out.println("输入数组下标为" + c + "的元素: ");
            int d = input.nextInt();
            nums[c] = d;
            c++;
        }

        System.out.print("是否进行对数组nums的访问(Y/N): ");
        String x = input.next();
        if (x.equals("N") || x.equals("n")) {
            System.out.println("你TM怎么敢不是Yes呢!!!皮痒了???");
            System.out.println("请您重新运行代码哦!23");
            System.out.println();
        }
        while (x.equals("Y") || x.equals("y")) {
            System.out.print("输入访问数组的下标(0开始): ");
            int i = input.nextInt();//下标访问的接收
            if (i < 0 || i > nums.length - 1) {
                System.out.println("数组长度就10个! 你TM的输入啥啊!");
                continue;
            }
            if (i > 0 && i <= nums.length - 1) {
                System.out.println("nums" + "[" + i + "]: " + nums[i]);
                System.out.print("是否再一次对数组nums进行访问(Y/N): ");
                x = input.next();
            }
        }
        int sum = 0;//计算数组总和
        int f = 0;
        while (f < nums.length) {
            sum += nums[f];
            f++;
        }
        System.out.println("数组元素的总和: " + sum);
        System.out.println("欢迎您下次使用!!!");
    }
}

内存分析(推荐看视频很详细)

    • 存放new的对象和数组
    • 可以被所有的线程共享, 不会存放别的对象引用
    • 存放基本变量类型(会包含这个基本类型的具体数据)
    • 引用对象的变量(会存放这个引用在堆里的具体地址)
  • 方法区

    • 可以被所有线程共享
    • 包含了所有class和static变量
  • 栈是目录,堆是空间位置


静态初始化和动态初始化

  • **静态初始化: **由于静态初始化是包含创建和赋值的操作. 一旦被定义就无法更改元素个数

  • 动态初始化: 数组默认初始化, 它的元素相当于类的实例变量, 因此数组一经分配空间, 其中每个元素也被按照实例变量同样的方式被隐式初始化(int: 默认0; String: 默认null)

package Array;

public class Demo_1 {
    public static void main(String[] args) {
        //静态初始化: 创建+赋值
        //一旦定义, 数组元素个数不可改变
        //创建      赋值
        int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        System.out.println("数组a长度: " + a.length);
        System.out.println("a[0]: " + a[0]);//1
        System.out.println("a[1]: " + a[9]);//10


        //动态初始化:包含默认初始化
        //创建+分配空间(不赋值)
        int[] b = new int[10];
        System.out.println("数组b长度: " + b.length);
        b[0] = 10;
        System.out.println("初始化的b[0]: " + b[0]);
        System.out.println("未被初始化的b[1](使用默认值): " + b[1]);
    }
}

数组四个基本特点

  • 数组长度是确定的, 一旦被创建, 它的大小是不可改变
  • 元素和数组必须相同类型, 不允许出现混合类型
  • 数组中的元素可以是任何数据类型, 包括基本类型和引用类型
  • 数组变量属引用类型, 数组也可以看作对象, 数组中的元素相当于对象的成员变量
  • 数组本身就是对象, Java中对象是在堆中, 因此数组无论保存原始类型还是其他对象类型数组对象本身是在堆中的
  • 数组下标: 合法区间[0, length-1], 越界就报错

数组使用

  • 普通For循环

  • For-Each循环

  • 数组作方法入参

  • 数组作返回值

package Array;

public class ArrayForDemo {
    public static void main(String[] args) {
        int arrayf[] = {21, 33, 231, 23, 1};
        printArray2(arrayf);
        System.out.println("================================");
        int[] Revers = ReverseArray3(arrayf);//将反转后数组返回给新的数组
        printArray2(Revers);//利用打印数组元素的方法
        System.out.println("================================");
        //JDK1.5引入, 但没有下标, 当我们需要操作数组中的元素时,操作较难
        //打印数组元素
        //for (int arrays : array) {
        //    System.out.println("数组元素: " + arrays);
        //}
    }

    //打印数组元素的方法(增强型)(For-Each)
    //public static void printArray(int[] array) {
    //    for (int i : array) {
    //        System.out.println(i);
    //    }
    //}

    //打印数组元素的方法(普通For循环)(数组做参数)
    public static void printArray2(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.println("array[" + i + "] = " + array[i]);
        }
    }

    //反转数组元素的方法(数组做参数)(返回数组)
    public static int[] ReverseArray3(int[] array) {
        int[] result = new int[array.length];//创建反转后的返回数组
        System.out.println("反转后数组: ");
        int j = 0;
        //反转操作(利用多一个数组来存放反转后的数组元素)
        //for循环可以多次赋值;如下述
        //for (int i = 0, j = result.length - 1; i < array.length; i++, j--) {
        //  result[j] = array[i];
        //}
        for (int i = array.length - 1; i >= 0; i--) {
            result[j] = array[i];
            //System.out.println("array[" + j + "] = " + result[j]);
            j++;
        }
        return result;
    }
}

多维数组(点击观看详细介绍)

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

  • 概念解释: 当一维数组时就是一列a[0], a[1]…等小盒子(即元素); 当二维数组时,在计算机内部, 原本的一列a[0], a[1]…存放元素的小盒子长大了, a[0]变成可以存放一个一维数组的中盒子了, 即a[0][0]就是中盒子里的第1个小盒子, a[0][1]就是中盒子里的第2个小盒子,以此类推(类似套娃)

  • type [][] typeName = new type[typeLength1][typeLength2];
    //其中typeLength1和2必须是正整数
    //typeLength1行数
    //typeLength2列数
    int[][] a = new int[2][3];
    //数组类型[][] 数组名 = new 数据类型[2][3]
    //
    
  • 上述代码可以当作a是一个两行三列的数组

package Array;

import java.util.Arrays;

public class LargeArrays {
    public static void main(String[] args) {
        //多维数组
        /*[4][2]
            a[0]中盒子中的元素 1,2
            a[1]中盒子中的元素 2,3
            a[2]中盒子中的元素 5,6
            a[3]中盒子中的元素 8,1
         */
        int[][] LargeArrays = {{1, 2}, {2, 3}, {5, 6}, {8, 1}};
        System.out.print("输出LargeArrays[0]中盒子地址: ");
        System.out.println(LargeArrays[0]);//当打算使用这种输出中盒子,这种只会输出一个中盒子对象(我的理解是地址)
        System.out.print("输出中盒子LargeArrays[0]中的所有元素: ");
        System.out.println(Arrays.toString(LargeArrays[0]));//输出中盒子LargeArrays[0]中的所有元素
        System.out.println();
        System.out.println("===================================================================");
        System.out.print("利用方法打印LargeArrays[0]中的所有元素: ");
        printArray2(LargeArrays[0]);//输出中盒子a[0]中的元素
        System.out.println();
        System.out.println("===================================================================");
        System.out.println("利用System.out.println输出LargeArrays[0]中盒子: ");
        System.out.println(LargeArrays[0][0]);//输出中盒子中的第一个小盒子存放的数值
        System.out.println(LargeArrays[0][1]);//输出中盒子中的第一个小盒子存放的数值
        System.out.println();
        System.out.println("===================================================================");
        System.out.println("利用方法来依次输出中盒子中的小盒子: ");
        printArray1(LargeArrays.length, LargeArrays);
    }

    //打印数组元素的方法(普通)(数组做参数)
    public static void printArray2(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.print("array[" + i + "] = " + array[i]);
        }
        System.out.println();
    }

    public static void printArray1(int Length1, int[][] arrays) {//循环中盒子
        for (int x = 0; x < arrays.length; x++) {//循环小盒子
            System.out.println();
            System.out.println("中盒子" + "LargeArrays[0][" + x + "]" + ": ");
            for (int y = 0; y < arrays[x].length; y++) {
                System.out.print("小盒子array[" + x + "][" + y + "] = " + arrays[x][y] + "\t\t");
            }
            System.out.println();
            System.out.println("===================================================================");
        }

    }
}

Arrays类

  • 数组的工具类 java.util.Arrays
  • API中提供了工具类Arrays供我们使用,从对数据对象进行基本操作
  • Arrays类中方法都是static修饰的静态方法, 在使用时候可以直接使用类名进行调用, 而””不用”使用对象来调用(注意:是”不用”; 而不是”不能”)
  • static出现本类中,就可以直接调用; 若在于其他类中, 则需要”类名.方法名”调用
  • 常用功能:
  • 数组赋值: fill方法
  • 数组排序: sort方法, 按升序
  • 比较数组: equals方法比较数组中元素值是否相等
  • 查找数组元素: binarySearch方法对已排序好的数组进行二分查找法操作
  • 数组使用方法可以在之后慢慢查看文档或者学习
package Array;

import java.util.Arrays;

public class ArraysDemo_3 {
    public static void main(String[] args) {
        int[] a = {46, 22, 33, 41};

        //打印数组元素(后面尝试写了功能同样Arrays.toString的方法)
        System.out.println("打印数组元素: ");
        System.out.println(Arrays.toString(a));
        PrintArray(a);

        System.out.println();

        //排序数组
        System.out.println("排序后数组元素: ");
        Arrays.sort(a);//对数组进行排序操作
        PrintArray(a);
        System.out.println(Arrays.toString(a));

        System.out.println();

        //fill方法将数组中元素中全部重新赋值为0(val:0;)可更改填充数值
        System.out.println("重新填充数组元素: ");
        Arrays.fill(a, 0);//数组填充
        System.out.println(Arrays.toString(a));
    }

    public static void PrintArray(int[] a) {
        for (int i = 0; i < a.length; i++) {
            if (i == 0) {
                System.out.print("[");
            }
            if (i == a.length - 1) {
                System.out.print(a[i] + "]");
            } else {
                System.out.print(a[i] + ", ");
            }
        }
        System.out.println();
    }
}

冒泡排序

  • 比较前后相邻的二个数据,如果前面数据大于后面的数据,就将这二个数据交换。

  • 这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。

  • N=N-1,如果N不为0就重复前面二步,否则排序完成

package Array;

import java.util.Arrays;

public class BoboSort {
    public static void main(String[] args) {
        //冒泡排序
        int[] arrays = {16, 12, 32, 47, 5, 64, 71, 18, 19,};

        int[] temparr = Bubblesort(arrays, arrays.length);
        System.out.println(Arrays.toString(temparr));
    }

    public static int[] Bubblesort(int[] arr, int n) {
        int i, j;
        for (i = 0; i < n - 1; i++) {//外层循环(每一轮排序就找出未排序序列中最大值放在最后)
            //外层循环执行一次确定一个数值(9次循环确定9个值都在自己的应该的位置)

            for (j = 1; j < n - i; j++) {//内层循环主要负责相邻数值的对比(在此例子第一次需要8次相邻对比,后续因为外层循环确定一个数值,故-i)
                //因为外层循环执行一次,就确定一个数值,故-i是为了减少不必要的循环
                if (arr[j] < arr[j - 1]) {
                    //交换arr[j-1]和arr[j]
                    //temp暂时存放交换的数值(中转站)
                    int temp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        return arr;
    }
}

稀疏数组

  • 当一数组中大部分元素为0或同一值的数组时,可用稀疏数组来保存该数组
  • 稀疏数组处理:
    • 记录数组一个几行几列,有多少不同值
    • 把具有不同值的元素和行列值记录在一个小规模的数组中(即记录元素值和行列所在值),从而缩小规模
  • 稀疏数组代码
    • 首先设定原始数组大小
      • 设定黑白棋所在位置(可利用Scanner自行设定, 但以下代码我没写)
    • 原始数组转换成稀疏数组
      1. 获取原始数组中的有效值个数
      2. 利用有效值个数创建稀疏数组(已建立行列值和元素值)
    • 稀疏数组还原成原始数组
      • 提取稀疏数组中第2行开始的行列值和元素值
package Array;//注意包名

import java.util.Scanner;

public class DemoKongArrays {//注意类名和文件名的对应
    public static void main(String[] args) {
        //创建二维数组11*11
        //0: 没有棋子
        //1: 黑棋
        //2: 白棋
        
        //1.创建原始数组大小
        int[] RowColumn = InputLineRow();
        int[][] Array_1 = new int[RowColumn[0]][RowColumn[1]];

        //1-1.设定棋盘的黑白棋所在位置
        //下标由0开始; (检验时,以下设定的行列值都是+1)
        Array_1[1][2] = 1;//黑棋位置
        Array_1[5][3] = 2;//白棋位置

        System.out.println("输出原始数组: ");
        Arrayprint(Array_1);
        System.out.println("=====================================================");

        //2.转换稀疏数组
        //2-1.获取有效值的个数
        int count = CorrectArray2(Array_1);
        System.out.println("棋盘数组中的有效值: " + count);
        System.out.println("=====================================================");

        System.out.println("压缩后的数组: ");
        //2-2.遍历二维数组, 将非零值存放到的稀疏数组中
        int[][] Array_3 = KongArray2(count, Array_1);
        printArray1(Array_3);
        System.out.println("=====================================================");

        //3.还原原始数组: 读取稀疏数组的值
        int[][] Array_5 = UpdateArray(Array_3);//设定一个数组,存放从稀疏数组中提取的行列值和元素值
        //3-1输出还原的数组
        System.out.println("还原压缩后的数组");
        Arrayprint(Array_5);
    }

    public static int[] InputLineRow() {//输入数组需要的行列值; 返回一个存放了行列值的数组
        int[] LineRow = new int[2];
        System.out.println("Enter the number of rows and columns: ");
        Scanner sc = new Scanner(System.in);
        System.out.print("行: ");
        LineRow[0] = sc.nextInt();

        System.out.print("列: ");
        LineRow[1] = sc.nextInt();
        return LineRow;
    }

    public static int[][] Arrayprint(int[][] Array_1) {//输出棋盘数组
        for (int[] ints : Array_1) {//每行
            for (int anInt : ints) {//每列
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
        return Array_1;
    }

    public static int[][] UpdateArray(int[][] Array_3) {//读取压缩后的稀疏数组; 传入压缩后的稀疏数组, 返回还原后的棋盘数组
        int[][] Array_5 = new int[Array_3[0][0]][Array_3[0][1]];
        for (int i = 1; i < Array_3.length; i++) {//稀疏数组第一行是棋盘数组的行列值和有效值个数;所以i=1开始,而不是0
            Array_5[Array_3[i][0]][Array_3[i][1]] = Array_3[i][2];
        }
        return Array_5;
    }

    public static int CorrectArray2(int[][] Array_1) {//读取棋盘数组有效值的个数
        int count = 0;
        for (int i = 0; i < Array_1.length; i++) {//每行
            for (int j = 0; j < Array_1[i].length; j++) {//每列
                if (Array_1[i][j] != 0) {//当遍历时遇到!=0,即count+1=count
                    count++;
                }
            }
        }
        return count;
    }

    public static int[][] KongArray2(int count, int[][] Array) {//压缩棋盘数组; 传入棋盘有效值个数和棋盘数组, 返回压缩后的稀疏数组
        //遍历二维数组, 将非零值存放到稀疏数组中
        //创建一个存放行列值和元素值的稀疏数组数组
        int[][] Array_2 = new int[count + 1][3];
        //count+1是因为要多存放一个棋盘数组总共的行和列以及数组总共有的有效元素值个数
        Array_2[0][0] = 9;
        Array_2[0][1] = 9;
        Array_2[0][2] = count;
        int count_1 = 0;

        for (int i = 0; i < Array.length; i++) {//每行
            for (int j = 0; j < Array[i].length; j++) {//每列
                if (Array[i][j] != 0) {
                    count_1++;//先count_1++是因为上述已经存放了棋盘数组的总共行列值和有效元素值个数
                    Array_2[count_1][0] = i;//稀疏数组存放 行值
                    Array_2[count_1][1] = j;//稀疏数组存放 列值
                    Array_2[count_1][2] = Array[i][j];//存放 元素值
                }
            }
        }
        return Array_2;
    }

    public static void printArray1(int[][] arrays) {//输出压缩后的稀疏数组; 传入压缩后的稀疏数组
        System.out.println("输出稀疏数组(下标由0开始): ");

        for (int i = 0; i < arrays.length; i++) {//遍历中盒子中的所有小盒子
            if (i == 0) {
                System.out.println("\t\t\t\t\t\t\t" + "行值|列值|有效的元素值个数");
                System.out.print("棋盘数组的总共的行列值和有效值个数: ");
                System.out.println(arrays[i][0] + " | " + arrays[i][1] + " | " + arrays[i][2]);
                System.out.println();
                continue;
            }
            if (i > 0) {
                System.out.println("\t\t\t\t\t\t\t" + "行值|列值|元素值");
            }
            System.out.println("第" + i + "个有效的元素值所在的行列位置:   " + arrays[i][0] + " | " + arrays[i][1] + " | " + arrays[i][2]);
            System.out.println();
            //array[0]使用增强型For会输出array[0][1]...等
        }
    }
}