Java语言核心技术第07章-Java数组

1 数组概述

1.1 为什么需要数组

需求:统计某班级 50个学生的成绩,包括最高分、最低分、平均分、统计及格人数
分析:如果不使用数组,首先需要定义50个变量来分别记录每位学生的成绩,然后统计某班级50个学生的成绩,这样会很麻烦。
因此我们可以将所有的数据全部存储到一个容器中统一管理,并使用容器进行计算,例如求最高分、最低分、平均分、统计及格人数等等。
容器几乎无处不在
● 生活中的容器:水杯(装水等液体)、衣柜(装衣服等物品)、集装箱(装货物等)
● 程序中的容器:将内存中的多个数据存储到一起,每个数据称为该容器的元素,例如数组存储多个基本数据类型和引用数据类型、集合存储多个引用数据类型

1.2 数组介绍

数组(Array)是一组(多个)相同类型的数据按照一定的顺序排列的集合,并且使用一个名字(数组名)命名,然后通过编号的方式对这些数据进行统一管理(增删改查)
数组的本质就是一块连续的内存空间
数组本身是引用数据类型,而数组中的元素可以是任意数据类型,包括八种基本数据类型和引用数据类型
创建数组的对象会在堆内存中开辟一块连续的内存空间,占据的内存空间大小取决于数组的长度和数组中元素的类型

1.3 数组常见概念

  • 数组名:用于记录数组在内存中的地址信息,引用的是这块连续内存空间的首地址,操作数组名就可以操作它表示的那块连续的内存空间
  • 数组的元素(element):数组中存放的每个数据,元素的类型可以是基本数据类型,也可以是引用数据类型(二选一)
  • 数组的长度(length):数组中最多可以存放元素的个数,可以通过数组名.length属性获取,例如numbers.length就可以获取numbers数组的长度
  • 数组的下标(index):也被称为索引(index)元素在数组容器中的编号,下标从0开始到数组的长度减1(numbers.length-1)
  • 数组的遍历:遍历指的是将数组中的所有内容取出来的过程,取出来之后就可以进行其他操作

1.4 数组分类

● 按照维数来分类
○ 一维数组:如果说数组默认就是一维数组
○ 二维数组:存储多组数据,相当于二维表,一行代表一组数组,只是这里的二维表每一行长度可以不一样
● 按照数组的元素类型分类
○ 基本数据类型元素的数组
○ 引用数据类型元素的数组

1.5 数组特点

  1. 数组要求所有元素的数据类型相同
  2. 数组中的元素在内存中是依次紧密排列,有序的
  3. 数组属于引用类型,数组中的元素既可以是基本数据类型,又可以是引用数据类型
  4. 数组一旦初始化完成,其长度就确定了,并且其长度不能改变
  5. 创建数组对象会在内存中开辟一块连续的内存空间,数组占据空间的大小取决于数组的长度和数组中元素的类型
  6. 可以通过下标(索引)的方式访问指定位置的元素,速度很快(查找元素效率高)
  7. 增加和删除元素的时候可能会移动大量的元素,速度慢(增加和删除元素效率低)

2 一维数组基础

2.1 一维数组的声明与初始化

2.1.1 一维数组的声明

数组在使用之前必须要先声明和初始化

首先回顾下变量的声明和初始化

//变量的声明 数据类型 变量名;
int age;

//变量的赋值(初始化) 变量名 = 变量值; 
//初始化指的是第一次赋值
age = 18;

数组的声明语法格式

数据类型[] 数组名;
  • 数据类型指的是元素的数据类型,既可以是引用数据类型,还可以是基本数据类型。
  • 数组名其实就是变量名,需要遵守标识符的命名规则和命名规范,数组名是引用数据类型的变量名,因为它代表一组数据
//声明基本类型元素数组
int[] numbers;
double[] prices;
char[] chars;

//声明引用数据类型元素数组
String[] cities;

2.1.2 一维数组的初始化

2.1.2.1 一维数组的初始化介绍

初始化就是在内存中为数组容器开辟内存空间,并将数据存入容器的过程

初始化可以选择静态初始化和动态初始化两种方式,它们各自的使用场景不同。

数组静态初始化使用场景:需求中明确具体操作的数据时使用(数据已知)
数组的动态初始化使用场景:只明确元素个数,不明确具体数值时使用(数据未知)

2.1.2.2 数组的静态初始化

数组的静态初始化指的就是数组的变量赋值和元素赋值同时进行,本质是用静态数据(编译时已知)为数组初始化。此时数组的长度由静态数据的个数决定

数组的静态初始化语法格式:数组名 = new 数据类型[]{元素1,元素2,元素3};

numbers = new int[]{1, 2, 3, 4, 5, 6, 7, 8};
prices = new double[]{5399.0, 8899.0, 9899.0};

数组的声明和静态初始化也可以合并到一起

其语法格式为数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3};

  • new:关键字,创建数组使用的关键字。因为数组本身是引用数据类型,所以要用 new 创建数组实体
//数组的声明和静态初始化完整格式
int[] values =  new int[]{1, 2, 3, 4, 5, 6, 7, 8};

当声明和静态初始化在一个语句完成时, new 数据类型[] 可以省略,因为可以通过类型推断推断出元素的类型:数据类型[] 数组名 = {元素1,元素2,元素3};

//数组声明与静态初始化简化格式
String[]goods={"iPhone16","iPhone16 Pro","iPhone 16 Pro Max"};
2.1.2.3 数组的动态初始化

数组的动态初始化指的就是数组的变量赋值和元素赋值分开进行,动态初始化后只确定了元素的个数(即数组的长度),而元素值此时只是默认值,还并未真正赋给自己期望的值,真正期望的数据需要后续单独一个一个赋值。

数组的动态初始化语法格式:数组名= new 数据类型[数组的长度];

● 数组的长度,表示数组容器中可以最多存储多少个元素。数组有定长特性,长度一旦指定,不可更改。 和水杯道理相同:买了一个1升的水杯,总容量就是1升是固定的

//动态初始化数组
//动态初始化基本数据类型元素数组
int[]data=new int[5];
//动态初始化引用数据类型元素数组
String[]foods=new String[108];
  1. 编辑ArrayDeclarationInitialization.java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.1 一维数组的声明与初始化
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-01 9:18
 * @since Java21
 */
public class ArrayDeclarationInitialization {
    public static void main(String[] args) {
        //变量的声明与赋值
        //变量的声明
        int number;
        //变量的赋值,首次赋值叫初始化
        number = 10;
        //数组的声明语法格式: 数据类型[] 数组名;
        //数据类型既可以是基本数据类型,也可以是引用数据类型

        //声明基本类型元素数组
        int[] numbers;
        double[] prices;
        char[] chars;

        //声明引用数据类型元素数组
        String[] cities;

        //数组的初始化

        //静态初始化基本数据类型元素数组
        numbers = new int[]{1, 2, 4, 5, 7, 8, 9, 6, 3};
        prices = new double[]{100.0, 300.0, 500.0};
        chars = new char[]{'A', 'B', 'C', 'D', 'E', 'F'};

        //静态初始化引用数据类型元素数组
        cities = new String[]{"北京", "上海", "广州", "深圳"};

        //数组的声明和静态初始化完整格式
        int[] values =  new int[]{1, 2, 3, 4, 5, 6, 7, 8};

        //数组的声明与静态初始化简化格式
        String[] goods = {"iPhone16", "iPhone16 Pro", "iPhone 16 Pro Max"};


        //动态初始化数组
        //动态初始化基本数据类型元素数组
        int[] data = new int[5];
        //动态初始化引用数据类型元素数组
        String[] foods = new String[108];

    }
}

  1. 运行ArrayDeclarationInitialization.java

程序运行结果

2.2 一维数组元素访问

在数组完成初始化后,可以使用数组名[下标]访问数组中的元素

每个存到数组的元素都会自动有个编号,这个编号是从0开始,被称为数组的索引(index)或者是下标,下标的范围是[0,数组的长度-1],即[0,数组名.length-1],下标既可以是整型常量,也可以是整型表达式。

  1. 编辑ArrayElementGetSet .java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.2 一维数组元素访问
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-01 9:43
 * @since Java21
 */
public class ArrayElementGetSet {
    public static void main(String[] args) {
        //静态初始化基本数据类型元素数组
        double[] prices = new double[]{5399.0, 8899.0, 9899.0};
        //数组名[下标]访问元素,下标的取值范围是0到长度减1
        System.out.println("1.访问基本数据类型元素数组");
        System.out.println("第一个价格是" + prices[0]);
        System.out.println("第二个价格是" + prices[1]);
        System.out.println("第三个价格是" + prices[2]);
        //动态初始化引用数据类型元素数组
        String[] cities = new String[4];
        //给数组的每个元素赋值
        cities[0] = "北京";
        cities[1] = "上海";
        cities[2] = "广州";
        cities[3] = "深圳";
        System.out.println("2.访问引用数据类型元素数组");
        System.out.println("第一个城市是" + cities[0]);
        System.out.println("第二个城市是" + cities[1]);
        System.out.println("第三个城市是" + cities[2]);
        System.out.println("第四个城市是" + cities[3]);
    }
}

  1. 运行ArrayElementGetSet.java

程序运行结果

2.3 一维数组遍历

数组初始化完成以后就明确了数组的长度,通过数组名.length属性获取数组长度。

然后就可以通过循环结构遍历数组,数组的遍历(Traversal)是指按照一定的顺序,逐个访问数组中的每个元素,并对其执行某些操作的过程。这些操作包括求和、求最大值、平均值、最小值等等操作。

  1. 编辑ArrayTraversal.java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.3 一维数组遍历
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-01 9:46
 * @since Java21
 */
public class ArrayTraversal {
    public static void main(String[] args) {
        //静态初始化基本数据类型元素数组
        double[] prices = new double[]{5399.0, 8899.0, 9899.0};
        System.out.println("prices数组的长度是 " + prices.length);
        //数组名[下标]访问元素,下标的取值范围是0到长度减1
        System.out.println("1.遍历基本数据类型元素数组");
        for (int i = 0; i < prices.length; i++) {
            System.out.println("第" + (i + 1) + "个价格是" + prices[i]);
        }
        //动态初始化引用数据类型元素数组
        String[] cities = new String[4];
        System.out.println("cities数组的长度是 " + cities.length);
        //给数组的每个元素赋值
        cities[0] = "北京";
        cities[1] = "上海";
        cities[2] = "广州";
        cities[3] = "深圳";
        System.out.println("2.遍历引用数据类型元素数组");
        for (int i = 0; i < cities.length; i++) {
            System.out.printf("第%d个城市是%s\n", (i + 1), cities[i]);
        }
    }
}

  1. 运行ArrayTraversal.java

程序运行结果

2.4 一维数组元素默认初始化值

数组是引用数据类型,当我们使用动态初始化方式创建数组时,Java会根据数组元素的不同数据类型给元素赋不同的默认值(初始值)

数据类型默认值
整型(byte、short、int、long)0
浮点型(float、double)0.0
字符型(char)0或者’\u0000’
布尔型(boolean)false
引用数据类型(类、接口、数组、枚举、记录)null
  1. 编辑ArrayElementDefaultInitialization.java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.4 一维数组元素默认初始化值
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-01 9:52
 * @since Java21
 */
public class ArrayElementDefaultInitialization {
    public static void main(String[] args) {
        // 数组的动态初始化的语法格式
        //数据类型[] 数组名=new 数据类型[数组的长度];
        //动态初始化numbers数组 数组的元素是整数
        int[] ints = new int[3];
        for (int i = 0; i < ints.length; i++) {
            System.out.printf("numbers数组的下标为%d的元素值是%d\n", i, ints[i]);
        }

        //动态初始化了doubles数组 数组的元素都是小数
        double[] doubles = new double[3];
        for (int i = 0; i < doubles.length; i++) {
            System.out.printf("doubles数组的下标为%d的元素值是%.1f\n", i, doubles[i]);

        }
        //动态初始化了chars数组 数组的元素都是字符
        char[] chars = new char[3];

        for (int i = 0; i < chars.length; i++) {
            System.out.printf("chars数组的下标为%d的元素值是%c\n", i, chars[i]);
        }
        if (chars[0] == 0) {
            System.out.println("如果数组元素的数据类型是char,那么数组元素的默认值是整数0");
        }
        if (chars[0] == '\u0000') {
            System.out.println("如果数组元素的数据类型是char,那么数组元素的默认值是'\\u0000\'");

        }
        if (chars[0] == '0') {
            System.out.println("如果数组元素的数据类型是char,那么数组元素的默认值是整数0");
        }

        //动态初始化了booleans数组 数组的元素都是布尔值 默认值是false
        boolean[] booleans = new boolean[3];
        for (int i = 0; i < booleans.length; i++) {
            System.out.printf("booleans数组的下标为%d的元素值是%b\n", i, booleans[i]);

        }

        //动态初始化了string数组 数组的元素都是字符串 默认值是null

        String[] strings = new String[3];
        for (int i = 0; i < strings.length; i++) {
            System.out.printf("strings数组的下标为%d的元素值是%s\n", i, strings[i]);
        }

        if (strings[0] == null) {
            System.out.println("如果数组元素的数据类型是引用数据类型,那么数组元素的默认值是null");
        }
    }
}

  1. 运行ArrayElementDefaultInitialization.java

程序运行结果

2.5 一维数组使用注意事项

2.5.1 一维数组使用注意事项1

数组是多个相同类型的数据集合,实现对这些数据的统一管理,数组中的元素可以是任意数据类型,包括基本数据类型和引用数据类型,但是不能混用,即类型一致。

  1. 编辑ArrayWarning1.java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.5.1 一维数组使用注意事项1
 * 数组是多个相同类型的数据集合,实现对这些数据的统一管理,
 * 数组中的元素可以是任意数据类型,包括基本数据类型和引用数据类型,但是不能混用,即类型一致。
 * @author tony 18601767221@163.com
 * @version 2024-09-01 9:57
 * @since Java21
 */
public class ArrayWarning1 {
    public static void main(String[] args) {
        //编译错误 数组元素的类型必须一致
        int[] numbers = {1, 2, 3, 4, 5, 6, "hello"};
        //int可以自动提升为double
        double[] doubles = {10, 20, 30, 40, 50, 60};
        System.out.println("遍历doubles数组");
        for (int i = 0; i < doubles.length; i++) {
            System.out.println(doubles[i]);
        }

        //数组中的元素可以是任意数据类型,包括基本数据类型和引用数据类型,但是不能混用,即类型一致
        //定义一个String数组 数组元素的数据类型是引用类型
        String[] cities = {"北京", "上海", "广州", "深圳"};
        System.out.println("遍历cities数组");
        for (int i = 0; i < cities.length; i++) {
            System.out.println(cities[i]);
        }
    }
}

  1. 编译项目

编译结果:编译错误,不兼容的类型,java.lang.String无法转换为int

  1. 注释第14行
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.5.1 一维数组使用注意事项1
 * 数组是多个相同类型的数据集合,实现对这些数据的统一管理,
 * 数组中的元素可以是任意数据类型,包括基本数据类型和引用数据类型,但是不能混用,即类型一致。
 * @author tony 18601767221@163.com
 * @version 2024-09-01 9:57
 * @since Java21
 */
public class ArrayWarning1 {
    public static void main(String[] args) {
        //编译错误 数组元素的类型必须一致
        //int[] numbers = {1, 2, 3, 4, 5, 6, "hello"};
        //int可以自动提升为double
        double[] doubles = {10, 20, 30, 40, 50, 60};
        System.out.println("遍历doubles数组");
        for (int i = 0; i < doubles.length; i++) {
            System.out.println(doubles[i]);
        }

        //数组中的元素可以是任意数据类型,包括基本数据类型和引用数据类型,但是不能混用,即类型一致
        //定义一个String数组 数组元素的数据类型是引用类型
        String[] cities = {"北京", "上海", "广州", "深圳"};
        System.out.println("遍历cities数组");
        for (int i = 0; i < cities.length; i++) {
            System.out.println(cities[i]);
        }
    }
}

  1. 运行ArrayWarning1.java

程序运行结果

2.5.2 一维数组使用注意事项2

如果数组没有初始化,然后访问数组中的元素就会引发空指针异常

  1. 编辑ArrayWarning2.java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.5.2 一维数组使用注意事项2
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-01 10:01
 * @since Java21
 */
public class ArrayWarning2 {
    public static void main(String[] args) {
        //数组的声明
        int[] numbers;

        //数组的赋值 null表示数组没有引用任何堆内存空间的数据
        numbers = null;

        //数组的使用-打印数组
        System.out.println("1.numbers = " + numbers);
        //访问数组的第一个元素
        // NullPointerException
        System.out.println("2.numbers[0] = " + numbers[0]);


    }
}

  1. 运行ArrayWarning2.java

程序运行结果

  1. 解决空指针异常
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.5.2 一维数组使用注意事项2
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-01 10:01
 * @since Java21
 */
public class ArrayWarning2 {
    public static void main(String[] args) {
        //数组的声明
        int[] numbers;

        //数组的赋值 null表示数组没有引用任何堆内存空间的数据
        numbers = null;

        //数组的使用-打印数组
        System.out.println("1.numbers = " + numbers);
        //访问数组的第一个元素
        //NullPointerException
        //System.out.println("2.numbers[0] = " + numbers[0]);

        //解决空指针异常
        if (null != numbers) {
            System.out.println("3.numbers[0] = " + numbers[0]);
        }
    }
}

  1. 运行ArrayWarning2.java

程序运行结果

2.5.3 一维数组使用注意事项3

数组索引越界,当通过数组名[索引]访问指定元素,如果索引超过它的范围(0-数组长度减1)就会引发索引越界异常 ArrayIndexOutOfBoundsException

  1. 编辑ArrayWarning3.java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.5.3  一维数组使用注意事项3
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-01 10:24
 * @since Java21
 */
public class ArrayWarning3 {
    public static void main(String[] args) {
        //静态初始化整数数组
        int[] numbers = {10, 20, 30};
        //数组元素的下标范围是0到数组的长度减1

        //有效的索引范围
        System.out.println("numbers1数组的下标为0的元素值是" + numbers[0]);
        System.out.println("numbers1数组的下标为1的元素值是" + numbers[1]);
        System.out.println("numbers1数组的下标为2的元素值是" + numbers[2]);

        //无效的索引范围
        System.out.println("numbers1数组的下标为3的元素值是" + numbers[3]);
        System.out.println("numbers1数组的下标-1的元素值是" + numbers[-1]);
    }
}

  1. 运行ArrayWarning3.java

程序运行结果

第22行报ArrayIndexOutOfBoundsException异常

  1. 注释第22行

  1. 再次运行ArrayWarning3.java

程序运行结果

第23行报ArrayIndexOutOfBoundsException异常

  1. 注释第23行

  1. 再次运行ArrayWarning3.java

程序运行结果

2.5.4 一维数组使用注意事项4

数组赋值成功的前提是类型必须一致

  1. 编辑ArrayWarning4.java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.5.4 一维数组使用注意事项4
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-01 10:30
 * @since Java21
 */
public class ArrayWarning4 {
    public static void main(String[] args) {
        int[] intArray = new int[10];
        byte[] byteArray = new byte[10];
        //编译错误没因为int[]和byte[]是两种不同类型的引用变量
        intArray = byteArray;
        /*
            byteArray = [B@b4c966a
            intArray = [I@21d81eb93
         */
        System.out.println("byteArray = " + byteArray);
        System.out.println("intArray = " + intArray);
        int[][] twoDimensionArray = new int[10][10];
        //编译错误,int[]和int[][]是两种不同类型的引用变量
        intArray=twoDimensionArray;
        //intArray=和twoDimensionArray[0]是相同类型的引用变量int[]
        intArray = twoDimensionArray[0];
        //twoDimensionArray[0] = [I@7291c18f
        System.out.println("twoDimensionArray[0] = " + twoDimensionArray[0]);
    }
}

  1. 编译项目

编译结果:编译错误,不兼容的类型,byte[]无法转换为int[]

int[][]无法转换为int[]

  1. 注释不兼容的类型错误,即第15行和第24行
package net.ittimeline.java.core.array.onedimensional;

/**
 * 2.5.4 一维数组使用注意事项4
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-01 10:30
 * @since Java21
 */
public class ArrayWarning4 {
    public static void main(String[] args) {
        int[] intArray = new int[10];
        byte[] byteArray = new byte[10];
        //编译错误没因为int[]和byte[]是两种不同类型的引用变量
        //intArray = byteArray;
        /*
            byteArray = [B@b4c966a
            intArray = [I@21d81eb93
         */
        System.out.println("byteArray = " + byteArray);
        System.out.println("intArray = " + intArray);
        int[][] twoDimensionArray = new int[10][10];
        //编译错误,int[]和int[][]是两种不同类型的引用变量
        //intArray=twoDimensionArray;
        //intArray=和twoDimensionArray[0]是相同类型的引用变量int[]
        intArray = twoDimensionArray[0];
        //twoDimensionArray[0] = [I@7291c18f
        System.out.println("twoDimensionArray[0] = " + twoDimensionArray[0]);
    }
}

  1. 运行ArrayWarning4.java

程序运行结果

3 JVM内存模型

程序运行时会被加载到内存中,由于Java程序是运行在JVM之上的,Java程序的字节码文件会被JVM的类加载器(ClassLoader)加载到JVM内存中
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域有着各自不同的用途,以及创建和销毁时间。
Java将内存区域划分为5个部分:方法区(Method Area)、程序计数器(Program Counter Register)、本地方法栈)

内存区域说明
方法区存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据,Java程序第一次使用某个类,会将该类的字节文件加载(只会加载一次)到方法区。
存储对象(包括数组)的实例,new来创建的都存储在堆内存,例如new int[3],new Scanner(System.in),new Random()等等。堆内存中的数据都有个地址,在地址区域内的数据都有默认值,当堆内存中的数据没有任何指向,就会被垃圾回收器 GC根据垃圾回收算法回收
虚拟机栈存储正在运行的方法以及方法中的局部变量栈的特点是先进后出(例如子弹夹)JVM首先会调用main方法来执行程序,方法一旦被调用就会被加载到栈区,开辟一块新的空间执行该方法,方法执行完毕后就会弹栈(回收方法执行占用的空间)
本地方法栈当程序中调用了native的本地方法时,本地方法执行期间的内存区域
程序计数器程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖程序计数器来完成。

需要注意的是从JDK8开始取消方法区,新增元空间。把原来方法区的多种功能进行拆分,有的功能放到了堆中,有的功能放到了元空间中。

4 一维数组内存分析

4.1 一个一维数组内存分析

  1. 编辑SingleArrayMemory.java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 3.1 一个一维数组内存分析
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-02 7:28
 * @since Java21
 */
public class SingleArrayMemory {
    public static void main(String[] args) {
        // 数组动态初始化语法格式

        // 数据类型[] 数组名 = new 数据类型[长度];
        int[] numbers = new int[3];

        /*
           [I@b4c966a
           [ 表示当前是一个数组
           I 表示数组里面的元素都是int类型
           @ 表示一个分隔符
           b4c966a 数组真正的地址值(十六进制)
           平时我们习惯性把这个整体叫做数组的地址值

         */
        System.out.println(numbers);

        //使用数组名[下标]访问数组的元素
        System.out.println("动态初始化数组后:");
        System.out.println("访问整数数组第1个元素的初始值" + numbers[0]);
        System.out.println("访问整数数组第2个元素的初始值" + numbers[1]);
        System.out.println("访问整数数组第3个元素的初始值" + numbers[2]);

        numbers[0] = 100;
        numbers[1] = 200;
        numbers[2] = 300;
        //使用数组名[下标]访问数组的元素
        System.out.println("修改数组元素后:");
        System.out.println("访问整数数组第1个元素的初始值" + numbers[0]);
        System.out.println("访问整数数组第2个元素的初始值" + numbers[1]);
        System.out.println("访问整数数组第3个元素的初始值" + numbers[2]);
    }
}

  1. 运行SingleArrayMemory.java

程序运行结果

程序执行流程

  1. main方法进入虚拟机栈执行
  2. 创建数组,JVM会在堆内存中开辟空间存储数组
  3. 数组在内存中有自己的内存地址,以十六进制的数表示,例如0xb4c966a
  4. 数组中有三个元素,默认值为0
  5. JVM将数组的内存首地址赋值给引用类型变量numbers
  6. 变量numbers保存的数组在内存中的地址0xb4c966a,而不是一个具体的数值,因此被称为引用数据类型

Q:数组下标为什么是从0开始

A:因为第一个元素距离数组首地址间隔0个单元格

4.2 两个一维数组内存分析

  1. 编辑MultiArrayMemory.java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 4.2 两个一维数组内存分析
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-02 7:33
 * @since Java21
 */
public class MultiArrayMemory {
    public static void main(String[] args) {
        //两个数组在内存中是独立的,相互不影响的两个空间
        int[] arr1 = {100, 200, 300};

        System.out.println("第一个数组是" + arr1);
        System.out.println("第一个数组索引编号为0的元素值是 " + arr1[0]);

        int[] arr2 = {10, 20, 30};
        System.out.println("第二个数组是" + arr2);
        System.out.println("第二个数组索引编号为0的元素值是 " + arr2[0]);


        arr1[0] = 8;
        System.out.println("第一个数组索引编号为0的元素值是 " + arr1[0]);

    }
}

  1. 运行MultiArrayMemory.java

程序运行结果

4.3 两个引用指向同一个一维数组内存分析

  1. 编辑MultiReferenceSingleArrayMemory.java
package net.ittimeline.java.core.array.onedimensional;

import java.util.Arrays;

/**
 * 4.3  两个引用指向同一个一维数组内存分析
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-02 7:36
 * @since Java21
 */
public class MultiReferenceSingleArrayMemory {
    public static void main(String[] args) {
        //初始化numbers1数组
        int[] numbers1 = {10, 20, 30};
        System.out.println("numbers1 = " + numbers1);
        //初始化numbers2数组
        int[] numbers2 = numbers1;
        System.out.println("numbers2 = " + numbers2);
        System.out.println("numbers1数组的元素内容是" + Arrays.toString(numbers1));
        System.out.println("numbers2数组的元素内容是" + Arrays.toString(numbers2));
        System.out.println("将numbers2数组的0号索引元素的值修改为8");
        //将numbers2数组的0号索引元素的值修改为8
        numbers2[0] = 8;
        System.out.println("numbers1数组的元素内容是" + Arrays.toString(numbers1));
        System.out.println("numbers2数组的元素内容是" + Arrays.toString(numbers2));
    }
}

  1. 运行MultiReferenceSingleArrayMemory.java

程序运行结果

5 一维数组案例

5.1 统计个数

需求:定义一个数组存储1,2,3,4,5,6,7,8,9,10,遍历数组得到每个元素,统计数组所有元素能被3整除的数字有多少个

  1. 编辑StatisticsCount.java.java
package net.ittimeline.java.core.array.onedimensional;

import java.util.Arrays;

/**
 * 5.1 统计个数
 * 需求:定义一个数组存储1,2,3,4,5,6,7,8,9,10
 * 遍历数组得到每个元素,统计数组所有元素能被3整除的数字有多少个
 * @author tony 18601767221@163.com
 * @version 2024-09-02 7:49
 * @since Java21
 */
public class StatisticsCount {
    public static void main(String[] args) {
        //静态初始化数组
        int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        //存储能被3整除的数字个数
        int count = 0;
        //遍历数组
        for (int i = 0; i < numbers.length; i++) {
            //如果数组的元素能被3整除
            if (numbers[i] % 3 == 0) {
                //个数自增一次
                count++;
            }
        }
        System.out.printf("数组%s所有元素能被3整除的数字有%d个\n", Arrays.toString(numbers),count);
    }
}

  1. 运行StatisticsCount.java

程序运行结果

5.2 变化数据

需求:定义一个数组存储1,2,3,4,5,6,7,8,9,10

遍历数组得到每个元素

要求:

  1. 如果是奇数则将当前数值扩大两倍
  2. 如果是偶数则将当前数字变成原来的二分之一

分析:奇数乘以2,偶数除以2

  1. 编辑ChangeData.java
package net.ittimeline.java.core.array.onedimensional;

import java.util.Arrays;

/**
 * 5.2 变化数据
 * 需求:定义一个数组存储1,2,3,4,5,6,7,8,9,10
 * 遍历数组得到每个元素
 * 要求:
 * 1. 如果是奇数则将当前数值扩大两倍
 * 2. 如果是偶数则将当前数字变成原来的二分之一
 * 分析:奇数乘以2,偶数除以2
 * @author tony 18601767221@163.com
 * @version 2024-09-02 7:56
 * @since Java21
 */
public class ChangeData {
    public static void main(String[] args) {

        //静态初始化数组
        int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        System.out.println("静态初始化后数组元素内容是" + Arrays.toString(numbers));

        //遍历数组
        for (int i = 0; i < numbers.length; i++) {
            //如果是奇数则将当前数值扩大两倍
            if (numbers[i] % 2 != 0) {
                numbers[i] *= 2;
            } else {
                //如果是偶数则将当前数字变成原来的二分之一
                numbers[i] /= 2;
            }
        }
        System.out.println("变化数据后数组元素内容是" + Arrays.toString(numbers));
    }
}

  1. 运行ChangeData.java

程序运行结果

5.3 破解房东电话

需求:爱博家园单间短期出租 6 个月, 3550 元/月(水电煤公摊,网费 100 元/月),空调、卫生间、厨房齐全。屋内均是 IT 行业人士,喜欢安静。所以要求来租者最好是同行或者刚毕业的年轻人,爱干净、安静。根据以下程序破解房东电话号码

  1. 编辑CrackLandlordTelephone.java
package net.ittimeline.java.core.array.onedimensional;

/**
 * 5.3 破解房东电话
 * 需求:爱博家园单间短期出租 6 个月, 3550 元/月(水电煤公摊,网费 100 元/月),空调、卫生间、厨房齐全。
 * 屋内均是 IT 行业人士,喜欢安静。所以要求来租者最好是同行或者刚毕业的年轻人,爱干净、安静。
 * 根据以下程序破解房东电话号码
 * @author tony 18601767221@163.com
 * @version 2024-09-02 8:20
 * @since Java21
 */
public class CrackLandlordTelephone {
    public static void main(String[] args) {
        //手机号的数字
        int[] telephoneNumber = new int[]{8, 6, 1, 7, 2, 0};
        //手机号所有数字的索引
        int[] telephoneNumberIndex = {2, 0, 1, 5, 2, 3, 1, 3, 4, 4, 2};
        System.out.print("房东的电话号码是:");
        //手机号码一共11个数字
        for (int i = 0; i < telephoneNumberIndex.length; i++) {
            //telephoneNumberIndex[i] 表示手机号每个数字的索引
            //telephoneNumber[telephoneNumberIndex[i]] 表示手机号每个数字
            System.out.print(telephoneNumber[telephoneNumberIndex[i]]);
        }
    }
}

  1. 运行CrackLandlordTelephone.java

程序运行结果

5.4 输出英文星期几

需求:用一个数组保存星期一到星期天的 7 个英语单词,从键盘输入 1-7,显示对应的单词

  1. 编辑PrintWeek.java
package net.ittimeline.java.core.array.onedimensional;

import java.util.Scanner;

/**
 * 5.5 输出英文星期几
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-02 17:06
 * @since Java21
 */
public class PrintWeek {
    public static void main(String[] args) {
        //定义包含7个单词的数组
        String[] weeks = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
        //创建Scanner对象
        //System.in表示标准输入,也就是键盘输入
        //Scanner对象可以扫描用户从键盘输入的数据
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入数值(1~7)");
        int number = scanner.nextInt();
        if (number >= 1 && number <= 7) {
            System.out.printf("数值%d对应的星期是%s\n", number, weeks[number - 1]);
        } else {
            System.out.println("你的输入有误");
        }
        //关闭Scanner
        scanner.close();
    }
}

  1. 运行PrintWeek.java

程序运行结果

5.5 统计学生成绩

需求:提示从键盘输入指定人数的学生成绩,然后找出最高分,并输出学生成绩等级

成绩>=最高分-10 等级为’A’

成绩>=最高分-20 等级为’B’

成绩>=最高分-30 等级为’C’

其余 等级为’D’

  1. 编辑StatisticsScoreLevel.java
package net.ittimeline.java.core.array.onedimensional;

import java.util.Scanner;

/**
 * 5.5 统计学生成绩
 * 需求:提示从键盘输入指定人数的学生成绩,然后找出最高分,并输出学生成绩等级
 * 成绩>=最高分-10 等级为'A'
 * 成绩>=最高分-20 等级为'B'
 * 成绩>=最高分-30 等级为'C'
 * 其余 等级为'D'
 * @author tony 18601767221@163.com
 * @version 2024-09-02 17:11
 * @since Java21
 */
public class StatisticsScoreLevel {
    public static void main(String[] args) {
        //①创建Scanner对象、根据学生人数动态创建数组
        //创建Scanner对象
        //System.in表示标准输入,也就是键盘输入
        //Scanner对象可以扫描用户从键盘输入的数据
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入学生人数");
        int count=scanner.nextInt();
        //动态初始化数组存储学生成绩
        int[]scores=new int[count];
        //假设第一个学生成绩是最高分
        int max=scores[0];
        //②接收键盘输入的成绩,存储在scores数组中,并求最高分
        System.out.println("请输入"+count+"个学生成绩");
        for (int i = 0; i < count; i++) {
            int score = scanner.nextInt();
            scores[i]=score;

            if (scores[i]>max) {
                max=scores[i];
            }
        }

        System.out.println("最高分是"+max);
        
        //③根据成绩与最高分差值计算等级并打印输出
        String grade;
        for (int i = 0; i < scores.length; i++) {
            if (scores[i]>max-10) {
                grade="A";
            }else if(scores[i]>max-20) {
                grade="B";
            }else if (scores[i]>max-30) {
                grade="C";
            }else{
                grade="D";
            }
            System.out.printf("student %d is %d grade is %S \n",i,scores[i],grade);
        }

        //关闭Scanner
        scanner.close();
    }
}

  1. 运行StatisticsScoreLevel.java

程序运行结果

6 二维数组基础

6.1 二维数组介绍

如果可以把一维数组当作几何中的线性图形,那么二维数组就相当于是一个表格,像Excel中的表格、围棋棋盘一样。

对于二维数组的理解,可以看成是一维数组 array1 又作为另一个一维数组 array2 的元素而存在。
从数组底层的运行机制来看,其实没有多维数组。

int[][] data = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

6.2 二维数组声明和初始化

6.2.1 二维数组声明

一维数组的声明与初始化

int[] numbers=new int[]{1,2,3,4,5,6,7,8,9};

二维数组的声明

数据类型[][] 数组名;
  • 数据类型指的是元素的数据类型,既可以是引用数据类型,还可以是基本数据类型。
  • []表示一维数组,[][]表示二维数组
//二维数组的声明
int[][]intData;
double[][]doubleData;
String[][]stringData;

6.2.2 二维数组初始化

始化就是在内存中为数组容器开辟内存空间,并将数据存入容器的过程
二维数组初始化也有静态初始化和动态初始化两种方式,它们各自的使用场景不同。

二维数组静态初始化使用场景:需求中明确具体操作的数据时使用
二维数组的动态初始化使用场景:只明确元素个数,不明确具体数值时使用

6.2.2.1 二维数组静态初始化

二维数组静态初始化指的是数组变量的赋值和数组元素的赋值同时进行,本质是用静态数据(编译时已知)为数组初始化。此时数组的长度由静态数据的个数决定

二维数组静态初始化语法格式:数组名 = new 数据类型[][]{元素1,元素2,元素3};

二维数组的声明和静态初始化也可以合并到一起

其语法格式为数据类型[][]数组名 =new 数据类型[][]{元素1,元素2,元素3};

  • new:关键字,创建数组使用的关键字。因为数组本身是引用数据类型,所以要用 new 创建数组实体
  • 元素是一维数组,一维数组的元素个数可以不一致
/********二维数组声明和静态初始化****************/
int[][]intValues = new int[][]{{1, 2, 3}, {4, 5, 6,}, {7, 8}};
double[][] doubleValues = new double[][]{{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0}};
String[][]stringValues = new String[][]{{"上海", "北京", "深圳", "广州"}, {"纽约", "旧金山", "波士顿"}};

二维数组声明和静态初始化简写语法格式

数据类型[][] 数组名 = {元素1,元素2,元素3};

其中 new 数据类型[][] 可以省略,因为可以通过类型推断推断出元素的类型

String[][]pl={{"c","c++",},{"java","python","go"},{"javascript","typescript"},{"swift","kotlin"}};
6.2.2.1 二维数组动态初始化

二维数组动态初始化有两种语法格式

二维数组动态初始化语法格式1

数据类型[][] 数组名 =new 数据类型[外层元素个数][内层元素个数]
  • 外层元素个数指的就是一维数组的个数
  • 内层元素个数指的就是一维数组中元素的个数
double[][] sales = new double[4][3];

二维数组动态初始化语法格式2

数据类型[][] 数组名 =new 数据类型[外层元素个数][]
double[][] prices = new double[4][];
  1. 编辑TwoDimensionalArrayDeclarationInitialization.java
package net.ittimeline.java.core.array.twodimensional;

/**
 * 6.2 二维数组声明和初始化
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-02 18:53
 * @since Java21
 */
public class TwoDimensionalArrayDeclarationInitialization {
    public static void main(String[] args) {
        /******************二维数组的声明******************/
        int[][] intData;
        double[][] doubleData;
        String[][] stringData;

        /******************二维数组声明和静态初始化******************/
        //静态初始化:数值变量的赋值和数组元素的赋值同时进行
        /*
            {1, 2, 3}, {4, 5, 6,}, {7, 8}表示外层元素
            1,2,3,4,5,6,7,8表示内层元素
         */
        int[][] intValues = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8}};
        double[][] doubleValues = new double[][]{{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0}};
        String[][] stringValues = new String[][]{{"上海", "北京", "深圳", "广州"}, {"纽约", "旧金山", "波士顿"}};

        /******************二维数组声明和静态初始化简化格式******************/

        String[][] pl = {{"c", "c++",}, {"java", "python", "go"}, {"javascript", "typescript"}, {"swift", "kotlin"}};

        /******************二维数组动态初始化两种方式******************/
        //动态初始化:数组变量的赋值和数组元素的赋值分开进行

        /******************二维数组动态初始化方式1******************/

        //4表示外层元素个数
        //3表示内层元素个数
        double[][] sales = new double[4][3];

        /******************二维数组动态初始化方式2******************/
        //4表示外层元素个数,内层元素个数不确定
        double[][] prices = new double[4][];
    }
}

  1. 运行TwoDimensionalArrayDeclarationInitialization.java

程序运行结果

6.3 二维数组元素访问

数组初始化(静态初始化、动态初始化)完成后,要访问二维数组中的元素(内层元素),你需要指定两个索引:第一个索引用于选择内部数组(行),第二个索引用于选择该内部数组中的元素(列),例如data[0][0]是访问二维数组data的第一行第一列的元素,而data[0][1]是访问二维数组的第一行第二列的元素,依次类推。
但是data[0]是访问二维数组第一个外层元素的内存地址

  1. 编辑TwoDimensionalArrayElementGetSet.java
package net.ittimeline.java.core.array.twodimensional;

/**
 * 6.3 二维数组元素访问
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-02 18:59
 * @since Java21
 */
public class TwoDimensionalArrayElementGetSet {
    public static void main(String[] args) {
        System.out.println("1.二维数组静态初始化与访问");
        //声明和静态初始化二维数组
        int[][] data = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
        //打印输出二维数组
        /*
            data = [[I@b4c966a
            [[ 表示为二维数组
            I 表示int
            @ 表示一个分隔符
            b4c966a 数组的地址值(十六进制)
           平时我们习惯性把这个整体叫做数组的地址值
         */
        System.out.println("data = " + data);
        //访问二维数组的元素:通过数组名[下标]访问
        //此时获取的是二维数组中的第一个元素{1,2,3}
        //此时打印输出的是一维数组的地址值
        System.out.println("二维数组第一行元素data[0] = " + data[0]);
        //此时获取的是二维数组第一个元素{1,2,3}的1
        System.out.println("二维数组data第一行第一列的元素data[0][0] = " + data[0][0]);
        //此时获取的是二维数组第一个元素{1,2,3}的3
        System.out.println("二维数组data第一行第三列的元素data[0][2] = " + data[0][2]);
        //此时获取的是二维数组第一个元素{7,8,9}的9
        System.out.println("二维数组data第三行第三列的元素data[2][2] = " + data[2][2]);

        System.out.println("2.二维数组动态初始化与访问");
        //声明和动态初始化二维数组
        double[][] sales = new double[4][3];
        //给二维数组的第一个元素(一维数组)赋值
        sales[0][0] = 4.68;
        sales[0][1] = 4.78;
        sales[0][2] = 4.88;

        //给二维数组的第二个元素(一维数组)赋值
        sales[1][0] = 6.68;
        sales[1][1] = 6.78;
        sales[1][2] = 6.88;

        //给二维数组的第三个元素(一维数组)赋值
        sales[2][0] = 5.68;
        sales[2][1] = 5.78;
        sales[2][2] = 5.88;
        //给二维数组的第四个元素(一维数组)赋值
        sales[3][0] = 7.68;
        sales[3][1] = 7.78;
        sales[3][2] = 7.88;
        System.out.println("二维数组sales第一行第二列的元素sales[0][1] = " + sales[0][1]);
        System.out.println("二维数组sales第二行第三列的元素sales[1][2] = " + sales[1][2]);
        System.out.println("二维数组sales第四行第三列的元素sales[3][2] = " + sales[3][2]);

        //声明和动态初始化二维数组
        String[][] cities = new String[2][];
        //初始化二维数组第一个元素
        cities[0] = new String[4];
        cities[0][0] = "上海";
        cities[0][1] = "北京";
        cities[0][2] = "广州";
        cities[0][3] = "深圳";
        //初始化二维数组第二个元素
        cities[1] = new String[3];
        cities[1][0] = "纽约";
        cities[1][1] = "旧金山";
        cities[1][2] = "波士顿";
        System.out.println("二维数组cities第一行第四列的元素cities[0][3] = " + cities[0][3]);
        System.out.println("二维数组cities第二行第三列的元素cities[1][2] = " + cities[1][2]);
    }
}

  1. 运行TwoDimensionalArrayElementGetSet.java

程序运行结果

6.4 二维数组遍历

二维数组初始化完成以后就明确了数组的长度,可以通过数组名.length属性获取二维数组长度。

然后就可以通过循环结构遍历数组的每个元素,遍历指的就是将数组的每个元素分别获取出来,此时取出来的每个外层元素都是一维数组,因此还需要嵌套一个循环,遍历取出外层每个一维数组的内层元素。

  1. 编辑TwoDimensionalArrayTraversal.java
package net.ittimeline.java.core.array.twodimensional;

/**
 * 6.4 二维数组遍历
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-03 9:38
 * @since Java21
 */
public class TwoDimensionalArrayTraversal {
    public static void main(String[] args) {
        //1.静态初始化二维数组
        int[][] numbers = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
        System.out.println("二维数组numbers的长度是" + numbers.length);
        System.out.println("二维数组numbers的第一个元素的长度是" + numbers[0].length);
        System.out.println("二维数组numbers的第二个元素的长度是" + numbers[1].length);
        System.out.println("二维数组numbers的第三个元素的长度是" + numbers[2].length);
        System.out.println("******************1.遍历二维数组numbers******************");
        //外层循环控制行数,遍历每个元素(一维数组)
        for (int i = 0; i < numbers.length; i++) {
            //内层循环控制列数,遍历每个一维数组的元素
            for (int j = 0; j < numbers[i].length; j++) {
                System.out.print(numbers[i][j] + "\t");
            }
            //换行
            System.out.println();
        }

        //2.声明和动态初始化二维数组
        String[][] cities = new String[2][];
        //初始化二维数组第一个元素
        cities[0] = new String[4];
        cities[0][0] = "上海";
        cities[0][1] = "北京";
        cities[0][2] = "广州";
        cities[0][3] = "深圳";
        //初始化二维数组第二个元素
        cities[1] = new String[3];
        cities[1][0] = "纽约";
        cities[1][1] = "旧金山";
        cities[1][2] = "波士顿";
        System.out.println("二维数组cities的长度是" + cities.length);
        System.out.println("二维数组cities的第一个元素的长度是" + cities[0].length);
        System.out.println("二维数组cities的第二个元素的长度是" + cities[1].length);
        System.out.println("******************2.遍历二维数组cities******************");
        //外层循环控制行数,遍历每个元素(一维数组)
        for (int i = 0; i < cities.length; i++) {
            //内层循环控制列数,遍历每个一维数组的元素
            for (int j = 0; j < cities[i].length; j++) {
                System.out.print(cities[i][j] + " ");
            }
            //换行
            System.out.println();
        }
    }
}

  1. 运行TwoDimensionalArrayTraversal.java

程序运行结果

6.5 二维数组元素初始化默认值

对于二维数组动态初始化语法格式1:数据类型[][] 数组名 =new 数据类型[外层元素个数][内层元素个数]

  • 外层元素默认存储地址值
  • 内层元素根据不同数据类型存储不同的默认值
数据类型默认值
整型(byte、short、int、long)0
浮点型(float、double)0.0
字符型(char)0或者’\u0000’
布尔型(boolean)false
引用数据类型(String等等)null

二维数组动态初始化方式1-数组元素是整数一维数组初始化默认值

二维数组动态初始化方式1-数组元素是小数一维数组初始化默认值

二维数组动态初始化方式1-数组元素是布尔一维数组初始化默认值

二维数组动态初始化方式1-数组元素是字符串一维数组初始化默认值

对于二维数组动态初始化语法格式2:数据类型[][] 数组名 =new 数据类型[外层元素个数][]

  • 外层元素默认存储null
  • 内层元素此时不存在,如果访问会引发NullPointerException

  1. 编辑TwoDimensionalArrayDefaultInitializationValue.java
package net.ittimeline.java.core.array.twodimensional;

/**
 * 6.5 二维数组元素初始化默认值
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-03 9:47
 * @since Java21
 */
public class TwoDimensionalArrayDefaultInitializationValue {
    public static void main(String[] args) {
         /*
            二维数组动态初始化语法格式1:二维数组元素初始化默认值
            外层元素默认存储地址值
            内层元素根据不同数据类型存储不同的默认值
         */
        int[][] intData1 = new int[4][3];
        //外层元素默认值 地址值
        System.out.println("intData1[0] = " + intData1[0]);
        System.out.println("intData1[1] = " + intData1[1]);

        //内层元素默认值 0
        System.out.println("intData1[0][0] = " + intData1[0][0]);
        System.out.println("intData1[1][0] = " + intData1[1][0]);

        double[][] doubleData1 = new double[4][3];
        //外层元素默认值 地址值
        System.out.println("doubleData1[0] = " + doubleData1[0]);
        System.out.println("doubleData1[1] = " + doubleData1[1]);

        //内层元素默认值 0.0
        System.out.println("doubleData1[0][0] = " + doubleData1[0][0]);
        System.out.println("doubleData1[1][0] = " + doubleData1[1][0]);

        boolean[][] booleanData1 = new boolean[4][3];
        //外层元素默认值 地址值
        System.out.println("booleanData1[0] = " + booleanData1[0]);
        //内层元素默认值 false
        System.out.println("booleanData1[0][0] = " + booleanData1[0][0]);
        System.out.println("booleanData1[1][1] = " + booleanData1[1][1]);



        String[][] stringData1 = new String[4][3];
        //外层元素默认值 地址值
        System.out.println("stringData1[0] = " + stringData1[0]);
        System.out.println("stringData1[1] = " + stringData1[1]);

        //内层元素默认值 null
        System.out.println("stringData1[0][0] = " + stringData1[0][0]);
        System.out.println("stringData1[1][0] = " + stringData1[1][0]);
         /*
            二维数组动态初始化语法格式2:二维数组元素初始化默认值
            外层元素默认存储null
            内层元素此时不存在,如果访问会引发NullPointerException
         */

        int[][] intData2 = new int[4][];
        System.out.println("intData2 = " + intData2);
        //外层元素默认值 null
        System.out.println("intData2[0] = " + intData2[0]);
        //内层元素不存在,如果调用会引发NullPointerException异常
        System.out.println("intData2[0][1]= " + intData2[0][1]);


        String[][] stringData2 = new String[4][];
        System.out.println("stringData2 = " + stringData2);
        //外层元素默认值 null
        System.out.println("stringData2[0] = " + stringData2[0]);
        //内层元素不存在,如果调用会引发NullPointerException异常
        System.out.println("stringData2[0][1]= " + stringData2[0][1]);




    }
}

  1. 运行TwoDimensionalArrayDefaultInitializationValue.java

程序运行结果

7 二维数组内存分析

7.1 二维数组静态初始化内存分析

7.1.1 二维数组静态初始化内存分析案例1

静态初始化二维数组arr

int[][] arr = new int[][]{{10, 20, 30}, {40, 50, 60}, {70, 80,90}};

7.1.2 二维数组静态初始化内存分析案例2

静态初始化二维数组arr

double[][] arr = new int[][]{{10.0, 20.0, 30.0}, {40.0, 50.0, 60.0}, {70.0, 80.0}};
arr[0][0]=100.0;
arr[2][1]=800.0;

7.2 二维数组动态初始化内存分析

7.2.1 二维数组动态初始化内存分析案例1

动态初始化二维数组arr

int[][]arr=new int[2][3];
arr[0][0]=10;
arr[0][2]=30;
arr[1][0]=50;
arr[1][2]=70;

7.2.2 二维数组动态初始化内存分析案例

动态初始化二维数组arr

 double[][]arr=new double[3][];
 arr[0]=new double[]{10.0,20.0,30.0};
 arr[1]=new double[2];
 arr[1][0]=80.0;
 arr[1][1]=100.0;
 arr=new double[3][];

8 二维数组案例

8.1 求全年的总销售额

需求:一家商场每个季度的销售额如下:单位万元。

一季度:20,30,40

二季度:10,35,42

三季度:21,32,49

四季度:51,45,78

要求:分别中四个数组将每一个季度的营业额存储,再把4个数组存储到一个大数组中。

求出全年的总销售额

  1. 编辑StatisticsFullYearSales.java
package net.ittimeline.java.core.array.twodimensional;

/**
 * 8.1 求全年的总销售额
 * 需求:一家商场每个季度的销售额如下:单位万元。
 * 一季度:20,30,40
 * 二季度:10,35,42
 * 三季度:21,32,49
 * 四季度:51,45,78
 * 要求:分别中四个数组将每一个季度的营业额存储,再把4个数组存储到一个大数组中。
 * 求出全年的总销售额
 * @author tony 18601767221@163.com
 * @version 2024-09-03 14:42
 * @since Java21
 */
public class StatisticsFullYearSales {
    public static void main(String[] args) {
        //
        int totalSales = 0;
        //定义二维数组保存全年的销售额
        int[][] sales = {{20, 30, 40}, {10, 35, 42}, {21, 32, 49}, {51, 45, 78}};

        for (int i = 0; i < sales.length; i++) {
            for (int j = 0; j < sales[i].length; j++) {
                totalSales+=sales[i][j];
            }
        }
        System.out.println("全年的总销售额是" + totalSales + "万元");
    }
}

  1. 运行StatisticsFullYearSales.java

程序运行结果

8.2 杨辉三角

需求:使用二维数组打印10行的杨辉三角,效果如下图所示

1	
1	1	
1	2	1	
1	3	3	1	
1	4	6	4	1	
1	5	10	10	5	1	
1	6	15	20	15	6	1	
1	7	21	35	35	21	7	1	
1	8	28	56	70	56	28	8	1	
1	9	36	84	126	126	84	36	9	1	

分析

  1. 第一行有1个元素,第n行有n个元素
  2. 每一行的第一个元素和最后一个元素都是1
  3. 从第三行开始,每行的第2个元素到倒数第2个元素的范围内,每个元素等于上一行的同一列与上一行同一列左边的一列之和

8.2.1 实现方式1

  1. 编辑YangHuiTriangleV1.java
package net.ittimeline.java.core.array.twodimensional;

/**
 * 8.2 杨辉三角
 * 需求:使用二维数组打印10行的杨辉三角,效果如下图所示
 1
 1	1
 1	2	1
 1	3	3	1
 1	4	6	4	1
 1	5	10	10	5	1
 1	6	15	20	15	6	1
 1	7	21	35	35	21	7	1
 1	8	28	56	70	56	28	8	1
 1	9	36	84	126	126	84	36	9	1

 * 分析
 * 1. 第一行有1个元素,第n行有n个元素
 * 2. 每一行的第一个元素和最后一个元素都是1
 * 3. 从第三行开始,每行的第2个元素到倒数第2个元素的范围内,每个元素等于上一行的同一列与上一行同一列左边的一列之和

 * 实现方式1
 * @author tony 18601767221@163.com
 * @version 2024-09-03 14:48
 * @since Java21
 */
public class YangHuiTriangleV1 {
    public static void main(String[] args) {
        int row=10;
        //动态初始化二维数组 此时只能确定二维数组的行数
        int[][]arr=new int[row][];

        //给数组元素赋值
        //外层循环控制行数
        for (int i = 0; i <arr.length ; i++) {
            //第1行有1列 第n行有n列
            arr[i]=new int[i+1];
            //内层循环控制每行的列数
            for (int j = 0 ;j <arr[i].length ; j++) {
                //每行第一列和最后一列都是1
                if (j==0||j==arr[i].length-1){
                    arr[i][j]=1;
                }else{
                    //从第三行开始,每行的第2个元素到倒数第2个元素的范围内,每个元素等于上一行的同一列与上一行同一列左边的一列之和
                    arr[i][j]=arr[i-1][j-1]+arr[i-1][j];
                }
            }
        }
        //遍历二维数组
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j]+"\t");
            }
            //换行
            System.out.println();
        }
    }
}

  1. 运行YangHuiTriangleV1.java

程序运行结果

8.3.2 实现方式2

  1. 编辑YangHuiTriangleV2.java
package net.ittimeline.java.core.array.twodimensional;

/**
 * 8.2 杨辉三角
 * 需求:使用二维数组打印10行的杨辉三角,效果如下图所示
 * 1
 * 1	1
 * 1	2	1
 * 1	3	3	1
 * 1	4	6	4	1
 * 1	5	10	10	5	1
 * 1	6	15	20	15	6	1
 * 1	7	21	35	35	21	7	1
 * 1	8	28	56	70	56	28	8	1
 * 1	9	36	84	126	126	84	36	9	1
 * <p>
 * 分析
 * 1. 第一行有1个元素,第n行有n个元素
 * 2. 每一行的第一个元素和最后一个元素都是1
 * 3. 从第三行开始,每行的第2个元素到倒数第2个元素的范围内,每个元素等于上一行的同一列与上一行同一列左边的一列之和
 * <p>
 * 实现方式2
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-03 15:49
 * @since Java21
 */
public class YangHuiTriangleV2 {
    public static void main(String[] args) {
        int row = 10;
        //动态初始化二维数组 此时只能确定二维数组的行数
        int[][] arr = new int[row][];
        //外层循环控制行数
        for (int i = 0; i < arr.length; i++) {
            //第1行有1列 第n行有n列
            arr[i] = new int[i + 1];
            //每行第一列和最后一列都是1
            arr[i][0] = arr[i][i] = 1;
            //从第三行开始,每行的第2个元素到倒数第2个元素的范围内,每个元素等于上一行的同一列与上一行同一列左边的一列之和
            for (int j = 1; j < arr[i].length - 1; j++) {
                arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
            }
        }

        //遍历二维数组
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j] + "\t");
            }
            //换行
            System.out.println();
        }
    }
}

  1. 运行YangHuiTriangleV2.java

程序运行结果

9 数组常见算法

9.1 数值型数值特征值统计

9.1.1 统计数值

需求:定义一个int类型的一维数组,包含10个元素,分别赋值一些随机整数,然后求出所有元素的最大值、最小值、总和、平均值,并统计多少个元素比平均值小。

  1. 编辑StaticsEigenvalue.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 数值型数值特征值统计算法
 * 9.1.1 统计数值
 * 需求:定义一个int类型的一维数组,包含10个元素,分别赋值一些随机整数,然后求出所有元素的最大值、最小值、总和、平均值,并统计多少个元素比平均值小。
 * @author tony 18601767221@163.com
 * @version 2024-09-03 15:22
 * @since Java21
 */
public class StaticsEigenvalue {
    public static void main(String[] args) {
        //1.动态初始化方式创建数组
        int[] numbers = new int[10];
        //2.通过循环给数组元素赋值
        for (int i = 0; i < numbers.length; i++) {
            int number = (int) (Math.random() * (99 - 10 + 1) + 10);
            numbers[i] = number;
        }
        System.out.println("数组中的元素是" + Arrays.toString(numbers));
        //3.求最大值
        int max = numbers[0];
        //4.求最小值
        int min = numbers[0];
        //5.求总和
        int sum = numbers[0];
        for (int i = 1; i < numbers.length; i++) {
            if (numbers[i] > max) {
                max = numbers[i];
            }
            if (numbers[i] < min) {
                min = numbers[i];
            }
            sum += numbers[i];
        }
        System.out.println("最大值是" + max);
        System.out.println("最小值是" + min);
        System.out.println("总和是" + sum);
        //6.求平均值
        int avg = sum / numbers.length;
        System.out.println("平均值是" + avg);
        //7.统计多少个值比平均值小
        int count = 0;
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] < avg) {
                count++;
            }
        }
        System.out.println("比平均值小的数字数量有" + count + "个");
    }
}

  1. 运行StaticsEigenvalue.java

程序运行结果

9.1.2 评委打分

需求:评委打分

分析以下需求,并且编写程序实现

在编程竞赛中,有10位评委为参赛的选手打分,分数分别为5, 4, 6, 8, 9, 7, 8, 9, 8, 5

求选手最后得分(去掉一个最高分和一个最低分后其余八位评委打分的平均值)

  1. 编辑JudgesScore.java
package net.ittimeline.java.core.array.algorithm;

/**
 * 数值型数值特征值统计算法
 * 9.1.2 评委打分
 * 需求:评委打分
 * 在编程竞赛中,有10位评委为参赛的选手打分,分数分别为5, 4, 6, 8, 9, 7, 8, 9, 8, 5
 * 求选手最后得分(去掉一个最高分和一个最低分后其余八位评委打分的平均值)
 * @author tony 18601767221@163.com
 * @version 2024-09-03 15:27
 * @since Java21
 */
public class JudgesScore {
    public static void main(String[] args) {
        //1.静态初始化数组保存评委的打分
        int[] scores = {5, 4, 6, 8, 9, 7, 8, 9, 8, 5};
        //2.求最高分最低分、总分
        int max = scores[0];
        int min = scores[0];
        int sum = 0;

        for (int i = 0; i < scores.length; i++) {
            //求最高分
            if (scores[i] > max) {
                max = scores[i];
            }
            //求最低分
            if (scores[i] < min) {
                min = scores[i];
            }
            //求总分
            sum += scores[i];
        }
        //3.求最后得分:去掉一个最高分和一个最低分后其余八位评委打分的平均值
        int score = (sum - max - min) / (scores.length - 2);
        System.out.println("去掉最高分和最低分之后,平均得分是" + score);
    }
}

  1. 运行JudgesScore.java

程序运行结果

9.2 数组元素赋值

9.2.1 生成不重复的元素

需求:创建一个长度为6的整数类型数组,要求数组元素的值在1-30之间,且是随机赋值,同时要求元素的值各不相同

9.2.1.1 实现方式1
  1. 编辑GeneratorUniqueElementV1.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.3.1 生成不重复的元素
 * 需求:创建一个长度为6的整数类型数组,要求数组元素的值在1-30之间,且是随机赋值,同时要求元素的值各不相同
 *
 * 实现方式1
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-03 15:38
 * @since Java21
 */
public class GeneratorUniqueElementV1 {

    public static void main(String[] args) {
        //声明并初始化一个名为arr的整数数组,长度为6。
        int[]arr=new int[6];
        //使用一个for循环来迭代数组arr的每一个位置,i的取值(索引)从0到5。
        for (int i = 0; i < arr.length; i++) {
            //生成1~30之间的随机整数
            int rand= (int)(Math.random()*30)+1;
            //标记思想:初始化一个布尔变量isExist为false,用于检查随机生成的数是否已经存在于数组中
            boolean isExist=false;
            //内部for循环,用于检查arr数组中从索引0到当前索引i(不包括i)是否存在与rand相等的元素。
            for (int j = 0; j <i ; j++) {
                //如果找到一个与rand相等的元素,则设置isExist为true并跳出内部循环。
                if (arr[j]==rand) {
                    //标记随机数已存在。
                    isExist=true;
                    //结束当前循环
                    break;
                }
            }
            //外层for循环,判断rand是否存在arr数组中
           // 如果 isExist 仍然为 false,即随机数不存在于数组中,则将 rand 赋值给 arr[i]
            if(!isExist) {
                //将随机数赋值给arr数组索引为i的元素
                arr[i]=rand;
            }
            //否则,如果rand已经存在于数组中,则需要重新生成一个新的随机数
            else{
                //递减外部循环的索引i,以便再次尝试为当前位置i分配一个不重复的随机数
                i--;
            }
        }
        System.out.println("数组中的元素内容是"+Arrays.toString(arr));
    }
}

  1. 运行GeneratorUniqueElementV1.java

程序运行结果

9.2.1.2 实现方式2
  1. 编辑GeneratorUniqueElementV2.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.3.1 生成不重复的元素
 * 需求:创建一个长度为6的整数类型数组,要求数组元素的值在1-30之间,且是随机赋值,同时要求元素的值各不相同
 * 实现方式2
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-03 16:12
 * @since Java21
 */
public class GeneratorUniqueElementV2 {
    public static void main(String[] args) {
        //声明并初始化一个名为 arr 的整数数组,长度为6。
        int[] arr = new int[6];
        //使用一个for循环来迭代数组arr的每一个位置,i的取值(索引)从0到5。
        for (int i = 0; i < arr.length; i++) {
            //计数器思想:初始化一个计数器 count,用来记录生成的随机数 rand 在数组 arr 中是否存在
            int count = 0;
            //生成1~30之间的随机整数
            int rand = (int) (Math.random() * 30) + 1;
            //内部for循环,用于检查arr数组中从索引0到当前索引当前索引i(不包括i)是否存在与rand相等的元素。
            for (int j = 0; j < i; j++) {
                //如果在数组 arr 中找到了一个等于rand的元素,则增加count的值,并退出内层循环。
                if (arr[j] == rand) {
                    //增加计数器count的值,表示找到了一个与rand相等的元素。
                    count++;
                    //立刻退出内层循环,因为只要找到一个相等的元素就足够了
                    break;
                }
            }
            //外层for循环,判断rand是否存在arr数组中
            //检查count是否等于1,如果等于1,则表示rand已经存在于数组中。
            if (count == 1) {
                i--;
            }
            //如果count不等于1,说明rand未在数组中找到,则将rand赋值给arr[i]。
            else {
                //将rand赋值给数组arr的当前索引位置 i。
                arr[i] = rand;
            }
        }
        System.out.println("数组中的元素内容是" + Arrays.toString(arr));
    }
}

  1. 运行GeneratorUniqueElementV2.java

程序运行结果

9.2.2 生成扑克牌

需求:生成并遍历54张扑克牌

  1. 编辑GeneratorPoker.java
package net.ittimeline.java.core.array.algorithm;

/**
 * 9.2.2 生成扑克牌
 * 需求:生成并遍历54张扑克牌
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-03 16:53
 * @since Java21
 */
public class GeneratorPoker {
    public static void main(String[] args) {
        //1.准备一副牌
        //4种花色
        String[] colors = {"♥", "♠", "♣", "♦"};
        //11种数字
        String[] numbers = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};

        //54张牌
        String[] pokers = new String[54];
        //0号索引放大王
        pokers[0] = "大王";
        //1号索引放小王
        pokers[1] = "小王";

        int index = 2;
        for (int i = 0; i < colors.length; i++) {
            String color = colors[i];
            for (int j = 0; j < numbers.length; j++) {
                String number = numbers[j];
                pokers[index] = color + number;
                index++;
            }
        }
        System.out.println("遍历扑克牌");
        for (int i = 0; i < pokers.length; i++) {
            System.out.print(pokers[i] + " ");
            if ((i + 12) % 13 == 0) {
                System.out.println();
            }
        }

    }
}

  1. 运行GeneratorPoker.java

程序运行结果

9.3 数组复制

数组赋值与数组赋值对比

  • 数组赋值:将array1赋值给array2,此时array1和array2地址相同,指向的是同一个堆内存的数组,如果修改array2,那么array1也会跟着修改。
  • 数组复制:将array1复制给array2,此时array1和array2地址不相同,因为array1和array2指向的不是同一个堆内存的数组。
  1. 编辑ArrayAssignmentDiffCopy.java
package net.ittimeline.java.core.array.algorithm;

/**
 * 9.3 数组复制
 * 数组赋值与数组赋值对比
 * ● 数组赋值:将array1赋值给array2,此时array1和array2地址相同,指向的是同一个堆内存的数组,如果修改array2,那么array1也会跟着修改。
 * ● 数组复制:将array1复制给array2,此时array1和array2地址不相同,因为array1和array2指向的不是同一个堆内存的数组。
 * @author tony 18601767221@163.com
 * @version 2024-09-03 18:24
 * @since Java21
 */
public class ArrayAssignmentDiffCopy {
    public static void main(String[] args) {
        {
            System.out.println("******************1.数组赋值******************");
            //数组赋值
            int[] array1 = {2, 3, 5, 7, 11};
            int[] array2 = array1;
            System.out.println("array1 = " + array1);
            System.out.println("array2 = " + array2);
            //修改array2元素的值
            for (int i = 0; i < array2.length; i++) {
                //将偶数索引的元素修改为索引值
                if (i % 2 == 0) {
                    array2[i] = i;
                }
            }
            System.out.println("遍历array1");
            for (int i = 0; i < array1.length; i++) {
                System.out.print(array1[i] + "\t");
            }
            //换行
            System.out.println();
        }

        {
            System.out.println("******************2.数组复制******************");
            int[] array1 = {2, 3, 5, 7, 11};
            //动态初始化数组array2,array2的长度和array1的长度相同
            int[] array2 = new int[array1.length];
            System.out.println("array1 = " + array1);
            System.out.println("array2 = " + array2);
            //将array1复制一份到array2
            //遍历array2
            for (int i = 0; i < array2.length; i++) {
                //将array1的元素赋值给array2
                array2[i] = array1[i];
            }
            //修改array2数组元素的值
            for (int i = 0; i < array2.length; i++) {
                if (i % 2 == 0) {
                    array2[i] = i;
                }
            }
            System.out.println("遍历array1");
            for (int i = 0; i < array1.length; i++) {
                System.out.print(array1[i] + "\t");
            }
            //换行
            System.out.println();
        }

    }
}

  1. 运行ArrayAssignmentDiffCopy.java

程序运行结果

9.4 元素反转

9.4.1 元素反转

需求:定义一个数组并存储1,2,3,4,5,反转之后是5,4,3,2,1

9.4.1.1 实现方式1

分析:

  • 假设array表示数组,i表示数组元素的索引,i的取值范围是0到array.length-1
  • 交换的元素就是array[i]和array[array.length-1-i]依次交换
  • 交换的次数是array.length/2
  1. 编辑ArrayReversalV1.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.4 数组反转
 * 需求:定义一个数组并存储1,2,3,4,5,反转之后是5,4,3,2,1
 * 分析:
  ● 假设array表示数组,i表示数组元素的索引,i的取值范围是0到array.length-1
  ● 交换的元素就是array[i]和array[array.length-1-i]依次交换
  ● 交换的次数是array.length/2
 * 实现方式1
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 8:41
 * @since Java21
 */
public class ArrayReversalV1 {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5};
        System.out.println("【实现方式1】数组反转之前数组元素内容是:" + Arrays.toString(array));

        for (int i = 0; i < array.length / 2; i++) {
            //交换array[i]和array[array.length - i - 1]位置的元素
            int temp = array[i];
            array[i] = array[array.length - i - 1];
            array[array.length - i - 1] = temp;
        }
        System.out.println("【实现方式1】数组反转之后数组元素内容是:" + Arrays.toString(array));

    }
}

  1. 运行ArrayReversalV1.java

程序运行结果

9.4.1.2 实现方式2

分析:

  • 假设array表示数组,i表示数组元素的头索引,j表示数组元素的尾索引
  • 交换的元素就是array[i]和array[j]依次交换
  • 交换的条件就是i小于j
  1. 编辑ArrayReversalV2.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.4 数组反转
 * 需求:定义一个数组并存储1,2,3,4,5,反转之后是5,4,3,2,1
 * 分析
 * ● 假设array表示数组,i表示数组元素的头索引,j表示数组元素的尾索引
 * ● 交换的元素就是array[i]和array[j]依次交换
 * ● 交换的条件就是i小于j
 * 实现方式2
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 8:58
 * @since Java21
 */
public class ArrayReversalV2 {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5};
        System.out.println("【实现方式2】数组反转之前数组元素内容是:" + Arrays.toString(array));
        for (int i = 0, j = array.length - 1; i < j; i++, j--) {
            //array[i]和array[j]位置的元素交换
            int temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
        System.out.println("【实现方式2】数组反转之前数组元素内容是:" + Arrays.toString(array));
    }
}

  1. 运行ArrayReversalV2.java

程序运行结果

9.4.2 对称数组

需求:判断数组是不是对称数组,例如 1 2 3 4 5 4 3 2 1 是一个对称数组,1 2 3 4 5 4 3 2 1 0不是一个对称数组

9.4.2.1 实现方式1

分析:

  • 假设array表示数组,i表示数组元素的索引,i的取值范围是从0到array.length-1
  • 判断是否为对称就是依次判断array[i]和array[array.length-1-i]是否相等,如果相等就是对称数组,否则就不是对称数组。
  1. 编辑SymmetricArrayV1.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.4.2 对称数组
 * 需求:判断数组是不是对称数组,例如 1 2 3 4 5 4 3 2 1 是一个对称数组,1 2 3 4 5 4 3 2 1 0不是一个对称数组
 * 分析:
 * 假设array表示数组,i表示数组元素的索引,i的取值范围是从0到array.length-1
 * 判断是否为对称就是依次判断array[i]和array[array.length-1-i]是否相等,如果相等就是对称数组,否则就不是对称数组。
 * 实现方式1
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 9:28
 * @since Java21
 */
public class SymmetricArrayV1 {
    public static void main(String[] args) {
        //对称数组测试用例
        //int[] array = {1, 2, 3, 4, 5, 4, 3, 2, 1};
        //非对称数组测试用例
        int[] array = {1, 2, 3, 4, 5, 4, 3, 2, 1, 0};
        boolean isSymmetric = true;
        for (int i = 0; i < array.length / 2; i++) {
            if (array[i] != array[array.length - i - 1]) {
                isSymmetric = false;
                break;
            }
        }
        if (isSymmetric) {
            System.out.println(Arrays.toString(array) + "是对称数组");
        } else {
            System.out.println(Arrays.toString(array) + "不是对称数组");
        }

    }
}

  1. 运行SymmetricArrayV1.java

程序运行结果

9.4.2.2 实现方式2

分析:

  • 假设array表示数组,i表示数组元素的头索引,j表示数组元素的尾索引
  • 判断是否为对称就是依次判断array[i]和array[j]是否相等,如果相等就是对称数组,否则就不是对称数组。
  • 判断的条件就是i小于j
  1. 编辑SymmetricArrayV2.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.4.2 对称数组
 * 需求:判断数组是不是对称数组,例如 1 2 3 4 5 4 3 2 1 是一个对称数组,1 2 3 4 5 4 3 2 1 0不是一个对称数组
 * 分析:
 * 假设array表示数组,i表示数组元素的头索引,j表示数组元素的尾索引
 * 判断是否为对称就是依次判断array[i]和array[j]是否相等,如果相等就是对称数组,否则就不是对称数组。
 * 判断的条件就是i小于j
 * 实现方式2
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 9:34
 * @since Java21
 */
public class SymmetricArrayV2 {
    public static void main(String[] args) {
        //对称数组测试用例
        int[] array = {1, 2, 3, 4, 5, 4, 3, 2, 1};
        //非对称数组测试用例
        //int[] array = {1, 2, 3, 4, 5, 4, 3, 2, 1, 0};

        boolean isSymmetric = true;
        for (int i = 0, j = array.length - 1; i < j; i++, j--) {
            if (array[i] != array[j]) {
                isSymmetric = false;
                break;
            }
        }
        if (isSymmetric) {
            System.out.println(Arrays.toString(array) + "是对称数组");
        } else {
            System.out.println(Arrays.toString(array) + "不是对称数组");
        }
    }
}

  1. 运行SymmetricArrayV2.java

程序运行结果

9.5 数组打乱元素顺序

9.5.1 数组打乱元素顺序

需求:定义数组并存储1,2,3,4,5,要求打乱数组中所有数据的顺序

分析:先借助Math.random()*array.length生成随机索引,然后再遍历数组,将数组中的元素和随机索引对应的元素交换即可

  1. 编辑ArrayShuffle.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.5.1 数组打乱元素顺序
 * 需求:定义数组并存储1,2,3,4,5,要求打乱数组中所有数据的顺序
 * 分析:先借助Math.random()*array.length生成随机索引,然后再遍历数组,将数组中的元素和随机索引对应的元素交换即可
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 10:15
 * @since Java21
 */
public class ArrayShuffle {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5};
        System.out.println("打乱数组元素顺序之前数组内容是" + Arrays.toString(array));
        for (int i = 0; i < array.length; i++) {
            int randIndex = (int) (Math.random() * array.length);
            int temp = array[i];
            array[i] = array[randIndex];
            array[randIndex] = temp;
        }
        System.out.println("打乱数组元素顺序之后数组内容是" + Arrays.toString(array));
    }
}

  1. 运行ArrayShuffle.java

程序运行结果

9.5.2 扑克牌洗牌

需求:打乱54张扑克牌的顺序

分析:

  1. 生成54张扑克牌

  2. 通过Math.random()*54生成随机索引

  3. 遍历54张牌,将每张扑克牌和随机索引对应的扑克牌进行交换

  4. 编辑GeneratorPokerShuffle.java

package net.ittimeline.java.core.array.algorithm;

/**
 * 9.5.2 扑克牌洗牌
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 10:39
 * @since Java21
 */
public class GeneratorPokerShuffle {
    public static void main(String[] args) {
        //1.准备一副牌
        //4种花色
        String[] colors = {"♥", "♠", "♣", "♦"};
        //11种数字
        String[] numbers = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};

        //54张牌
        String[] pokers = new String[54];
        //0号索引放大王
        pokers[0] = "大王";
        //1号索引放小王
        pokers[1] = "小王";

        int index = 2;
        for (int i = 0; i < colors.length; i++) {
            String color = colors[i];
            for (int j = 0; j < numbers.length; j++) {
                String number = numbers[j];
                pokers[index] = color + number;
                index++;
            }
        }

        //洗牌:打乱扑克牌顺序
        //遍历54张牌,将每张扑克牌和随机索引对应的扑克牌进行交换
        for (int i = 0; i < pokers.length; i++) {
            //通过Math.random()*54生成随机索引
            int randIndex = (int) (Math.random() * pokers.length);
            String temp = pokers[i];
            pokers[i] = pokers[randIndex];
            pokers[randIndex] = temp;
        }
        System.out.println("遍历扑克牌");
        for (int i = 0; i < pokers.length; i++) {
            System.out.print(pokers[i] + " ");
            if ((i + 12) % 13 == 0) {
                System.out.println();
            }
        }


    }
}

  1. 运行GeneratorPokerShuffle.java

程序运行结果

9.6 数组扩容与缩容

9.6.1 数组扩容

需求:现有数组int[] array= {1,2,3,4,5};,现将数组长度扩容1倍,并将10,20,30三个元素添加到array数组中,如何实现?

分析:

  1. 创建新数组newArray,新数组的长度是array的2倍

  2. 将原数组的内容复制到新数组

  3. 将10,20,30添加到新数组中

  4. 将新数组newArray赋值给数组array

  5. 编辑ArrayExpandingCapacity.java

package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.6.1 数组扩容
 * 需求:现有数组int[] array= {1,2,3,4,5};,现将数组长度扩容1倍,并将10,20,30三个元素添加到array数组中,如何实现?
 * 分析:
 * 1. 创建新数组newArray,新数组的长度是array的2倍
 * 2. 将原数组的内容复制到新数组
 * 3. 将10,20,30添加到新数组中
 * 4. 将新数组newArray赋值给数组array
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 10:51
 * @since Java21
 */
public class ArrayExpandingCapacity {
    public static void main(String[] args) {
        //静态出初始化数组array
        int[] array = {1, 2, 3, 4, 5};
        System.out.println("初始化后array数组的内容是" + Arrays.toString(array));
        //动态初始化新数组newArray,长度是原数组array的1倍
        int[] newArray = new int[array.length << 2];
        //int[] newArray = new int[array.length * 2];
        //将原数组的内容拷贝到新数组
        for (int i = 0; i < array.length; i++) {
            newArray[i] = array[i];
        }
        //将10,20,30添加到newArray数组中
        for (int i = 0; i < 3; i++) {
            newArray[array.length + i] = (i + 1) * 10;
        }
        //将newArray赋值给array
        array = newArray;
        System.out.println("扩容后array数组的内容是" + Arrays.toString(array));
    }
}

  1. 运行ArrayExpandingCapacity.java

程序运行结果

9.6.2 数组缩容

需求:现有数组 int[]array={1,2,3,4,5,6,7},现在需要删除数组中索引为4的元素

9.6.2.1 实现方式1

分析:

删除数组中索引为4的元素,也就是删除5

数组的长度一旦初始化后就不能改变,因此思路应该是将索引为5以后的元素依次赋值给索引为4以后的元素,并且将最后一个元素赋值为0

  1. 编辑ArrayReduceCapacityV1.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.6.2 数组缩容
 * 需求:现有数组 int[]array={1,2,3,4,5,6,7},现在需要删除数组中索引为4的元素
 * 分析:
 * 删除数组中索引为4的元素,也就是删除5,数组的长度一旦初始化后就不能改变
 * 因此思路应该是将索引为5以后的元素依次赋值给索引为4以后的元素,并且将最后一个元素赋值为0
 * 实现方式1
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 11:10
 * @since Java21
 */
public class ArrayReduceCapacityV1 {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6, 7};
        System.out.println("【实现方式1】初始化后数组元素内容是" + Arrays.toString(array));
        int removeIndex = 4;
        //将索引为5以后的元素依次赋值给索引为4以后的元素
        for (int i = removeIndex; i < array.length - 1; i++) {
            array[i] = array[i + 1];
        }
        //将最后一个元素赋值为0
        array[array.length - 1] = 0;
        System.out.println("【实现方式1】缩容后数组元素内容是" + Arrays.toString(array));
    }
}

  1. 运行ArrayReduceCapacityV1.java

程序运行结果

9.6.2.2 实现方式2

分析:

删除数组中索引为4的元素,也就是删除5

创建一个新数组newArray,长度是数组array.length-1

将除索引为4的元素复制到新数组newArray

将newArray赋值给array

  1. 编辑ArrayReduceCapacityV2.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.6.2 数组缩容
 * 需求:现有数组 int[]array={1,2,3,4,5,6,7},现在需要删除数组中索引为4的元素
 * 分析:
 * 删除数组中索引为4的元素,也就是删除5
 * 创建一个新数组newArray,长度是数组array.length-1
 * 将除索引为4的元素复制到新数组newArray
 * 将newArray赋值给array
 * 实现方式2
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 12:39
 * @since Java21
 */
public class ArrayReduceCapacityV2 {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6, 7};
        System.out.println("【实现方式2】初始化后数组元素内容是" + Arrays.toString(array));
        //创建一个新数组newArray,长度是数组array.length-1
        int[] newArray = new int[array.length - 1];
        int removeIndex = 4;
        //将除索引为4的元素复制到新数组newArray
        for (int i = 0; i < 4; i++) {
            newArray[i] = array[i];
        }
        for (int i = removeIndex; i < array.length - 1; i++) {
            newArray[i] = array[i + 1];

        }
        //将newArray赋值给array
        array = newArray;
        System.out.println("【实现方式2】缩容后数组元素内容是" + Arrays.toString(array));
    }
}

  1. 运行ArrayReduceCapacityV2.java

程序运行结果

9.7 数组元素查找

组元素查找主要分为线性查找和二分法查找两种方式

  1. 线性查找:优点是算法简单,缺点是查找效率低,执行的时间复杂度是O(N)
  2. 二分法查找:优点是查找效率高,执行的时间复杂度是0(logN),缺点是算法相对线性查找复杂,数据必须有序

9.7.1 线性查找

需求:定义数组int[] array = new int[]{34, 54, 3, 2, 65, 7, 34, 5, 76, 34, 67};,查找元素5是否在数组中出现过,如果出现输出首次出现的索引值

分析:遍历数组,将查找的元素和数组中的元素依次进行比较,如果第一次相等则表示出现过(找到了),此时记录对应的索引并终止循环,否则表示没有出现过(没找到)

9.7.1.1 实现方式1
  1. 编辑LinearSearchIntDataV1.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.7.1 线性查找
 * 需求:定义数组int[] array = new int[]{34, 54, 3, 2, 65, 7, 34, 5, 76, 34, 67};,查找元素5是否在数组中出现过,如果出现输出首次出现的索引值
 * 分析:遍历数组,将查找的元素和数组中的元素依次进行比较,如果第一次相等则表示出现过(找到了),此时记录对应的索引并终止循环,否则表示没有出现过(没找到)
 * 实现方式1
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 12:50
 * @since Java21
 */
public class LinearSearchIntDataV1 {
    public static void main(String[] args) {
        //静态初始化数组
        int[] array = new int[]{34, 54, 3, 2, 65, 7, 34, 5, 76, 34, 67};
        //查找元素的索引
        int index = -1;
        //查找的元素
        int target = 5;
        //遍历数组
        for (int i = 0; i < array.length; i++) {
            //如果数组的元素和查找的元素相等
            if (array[i] == target) {
                //将该元素的索引赋值给index
                index = i;
                //结束查找
                break;
            }
        }
        if (index != -1) {
            System.out.printf("【线性查找实现方式1】元素%d在数组%s的索引是%d\n", target, Arrays.toString(array), index);
        } else {
            System.out.printf("【线性查找实现方式1】数组%s中不存在元素%d\n", Arrays.toString(array), target);
        }
    }
}

  1. 运行LinearSearchIntDataV1.java

程序运行结果

9.7.1.2 实现方式2
  1. 编辑LinearSearchIntDataV2.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.7.1 线性查找
 * 需求:定义数组int[] array = new int[]{34, 54, 3, 2, 65, 7, 34, 5, 76, 34, 67};,查找元素5是否在数组中出现过,如果出现输出首次出现的索引值
 * 分析:遍历数组,将查找的元素和数组中的元素依次进行比较,如果第一次相等则表示出现过(找到了),此时记录对应的索引并终止循环,否则表示没有出现过(没找到)
 * 实现方式2
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 12:56
 * @since Java21
 */
public class LinearSearchIntDataV2 {
    public static void main(String[] args) {
        //静态初始化数组
        int[] array = new int[]{34, 54, 3, 2, 65, 7, 34, 5, 76, 34, 67};
        //查找的元素
        int target = 5;
        //遍历数组
        int i = 0;
        while (i < array.length) {
            //如果数组的元素和查找的元素相等
            if (array[i] == target) {
                //结束查找
                break;
            }
            i++;
        }
        if (i != array.length) {
            System.out.printf("【线性查找实现方式2】元素%d在数组%s的索引是%d\n", target, Arrays.toString(array), i);
        } else {
            System.out.printf("【线性查找实现方式2】数组%s中不存在元素%d\n", Arrays.toString(array), target);
        }
    }
}

  1. 运行LinearSearchIntDataV2.java

程序运行结果

9.7.1.3 实现方式3
  1. 编辑LinearSearchIntDataV3.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.7.1 线性查找
 * 需求:定义数组int[] array = new int[]{34, 54, 3, 2, 65, 7, 34, 5, 76, 34, 67};,查找元素5是否在数组中出现过,如果出现输出首次出现的索引值
 * 分析:遍历数组,将查找的元素和数组中的元素依次进行比较,如果第一次相等则表示出现过(找到了),此时记录对应的索引并终止循环,否则表示没有出现过(没找到)
 * 实现方式3
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 13:11
 * @since Java21
 */
public class LinearSearchIntDataV3 {
    public static void main(String[] args) {
        //静态初始化数组
        int[] array = new int[]{34, 54, 3, 2, 65, 7, 34, 5, 76, 34, 67};
        //查找的元素
        int target = 5;
        boolean isExists = false;
        //遍历数组
        for (int i = 0; i < array.length; i++) {
            //如果数组的元素和查找的元素相等
            if (array[i] == target) {
                isExists = true;
                System.out.printf("【线性查找实现方式3】元素%d在数组%s的索引是%d\n", target, Arrays.toString(array), i);
                //结束查找
                break;
            }
        }
        if (isExists == false) {
            System.out.printf("【线性查找实现方式3】数组%s中不存在元素%d\n", Arrays.toString(array), target);
        }
    }
}

  1. 运行LinearSearchIntDataV3.java

程序运行结果

9.7.2 二分法查找

需求:定义数组int[]array={2,4,5,8,12,15,19,26,37,49,51,66,89,100};,查找元素5是否在array数组中出现过,如果出现输出对应的索引值

分析:

  1. 编辑BinarySearchIntData.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;

/**
 * 9.7.2 二分法查找
 * 需求:定义数组int[]array={2,4,5,8,12,15,19,26,37,49,51,66,89,100};,查找元素51是否在array数组中出现过,如果出现输出对应的索引值
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 13:22
 * @since Java21
 */
public class BinarySearchIntData {
    public static void main(String[] args) {
        int[] array = {2, 4, 5, 8, 12, 15, 19, 26, 37, 49, 51, 66, 89, 100};
        //查找的目标元素
        int target = 5;
        //查找的目标元素索引
        int targetIndex = -1;
        //二分法查找的次数
        int count = 0;
        //头索引
        int head = 0;
        //尾索引
        int tail = array.length - 1;
        //循环条件是头索引小于等于尾索引
        while (head <= tail) {
            count++;
            //计算中间索引
            int middle = (head + tail) / 2;
            //查找的目标元素和中间值比较
            //如果目标元素比中间值大
            if (target > array[middle]) {
                //头索引=中间索引加1
                head = middle + 1;
            }
            //如果目标元素比中间值小
            else if (target < array[middle]) {
                //尾索引=中间值减1
                tail = middle - 1;
            }
            //找到了
            else {
                targetIndex = middle;
                //结束循环
                break;
            }
        }
        if (targetIndex != -1) {
            System.out.printf("目标元素%d在数组%s找到了,索引是%d,一共找了%d次\n", target, Arrays.toString(array), targetIndex, count);
        } else {
            System.out.printf("目标元素%d在数组%s没有找到\n", target, Arrays.toString(array));
        }
    }
}

  1. 运行BinarySearchIntData.java

程序运行结果

9.8 冒泡排序

9.8.1 冒泡排序介绍

冒泡排序的原理:对要进行排序的一堆数据,相邻的数据进行两两比较,将比较后较大的数据放在后面,也就是按照从小到大的升序排序,依次对所有的数据进行上述操作,直到所有的数据都按照要求完成排序

冒泡排序的特点:如果有n个数据,那么要比较n-1轮,每轮比较完毕后,下一轮就少比较一次,也就是说少一个数据参与比较

9.8.2 冒泡排序基础版

  1. 编辑BubbleSort.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;
import java.util.Scanner;

/**
 * 9.8.2 冒泡排序基础版
 * 冒泡排序的原理:对要进行排序的一堆数据,相邻的数据进行两两比较,将比较后较大的数据放在后面,也就是按照从小到大的升序排序,依次对所有的数据进行上述操作,直到所有的数据都按照要求完成排序
 * 冒泡排序的特点:如果有n个数据,那么要比较n-1轮,每轮比较完毕后,下一轮就少比较一次,也就是说少一个数据参与比较
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-04 13:46
 * @since Java21
 */
public class BubbleSort {
    public static void main(String[] args) {
        /*{
            System.out.println("******************原始版本数据升序冒泡排序实现******************");
            //排序的数据有5个
            int[] array = {24, 69, 88, 57, 13};
            System.out.println("排序之前数组的元素是" + Arrays.toString(array));

            //第一轮排序比较四次
            for (int j = 0; j < 4; j++) {
                if (array[j] > array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
            System.out.println("第一轮排序之后 数组的元素是" + Arrays.toString(array));

            //第二轮排序比较三次
            for (int j = 0; j < 3; j++) {
                if (array[j] > array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
            System.out.println("第二轮排序之后 数组的元素是" + Arrays.toString(array));


            //第三轮排序比较两次
            for (int j = 0; j < 2; j++) {
                if (array[j] > array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
            System.out.println("第三轮排序之后 数组的元素是" + Arrays.toString(array));


            //第四轮排序比较1次
            for (int j = 0; j < 1; j++) {
                if (array[j] > array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
            System.out.println("第四轮排序之后 数组的元素是" + Arrays.toString(array));
            System.out.println("排序之后数组的元素是" + Arrays.toString(array));

        }*/

        //① 准备测试数据
        //创建Scanner对象
        //System.in 标准输入,也就是键盘输入
        //Scanner对象可以扫描用户从键盘输入的数据
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入待排序整数的个数");
        int length = scanner.nextInt();
        System.out.println("请输入待排序的整数(每输完一个就回车)");
        //排序的数据有5个
        int[] array = new int[length];
        for (int i = 0; i < length; i++) {
            array[i] = scanner.nextInt();
        }

        //关闭Scanner
        scanner.close();
        //② 冒泡排序
        System.out.println("冒泡排序基础版【升序排序】之前数组的元素是" + Arrays.toString(array));
        int round = 0;
        //外层循环控制排序的轮数
        //一共比较array.length-1轮,每轮比较确定一个数的位置,例如第一轮确定最大值的位置,第二轮确定第二大的值的位置,依此类推
        //统计循环次数
        int totalCount = 0;
        for (int i = 0; i < array.length - 1; i++) {
            round++;
            int count = 0;
            //每轮比较的次数逐渐减少 假如有5个数据,第一轮比较4次,第二轮比较3次,第三轮比较2次,第四轮比较1次
            for (int j = 0; j < array.length - 1 - i; j++) {
                totalCount++;
                count++;
                //比较相邻的两个整数,如果前面的数大于后面的数
                if (array[j] > array[j + 1]) {
                    //就交换位置
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
                System.out.printf("第%d轮 第%d次比较,数组的元素是%s\n", round, count, Arrays.toString(array));
            }
        }
        System.out.println("冒泡排序基础版【升序排序】之后数组的元素是" + Arrays.toString(array));
        System.out.println("总循环次数是" + totalCount);
    }
}

  1. 运行BubbleSort.java

程序运行结果

9.8.3 冒泡排序优化版

在冒泡排序基础版基础上做以下优化

  1. 编辑BubbleSortOptimize.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;
import java.util.Scanner;

/**
 * 9.8 冒泡排序
 * 冒泡排序的原理:对要进行排序的一堆数据,相邻的数据进行两两比较,将比较后较大的数据放在后面,也就是按照从小到大的升序排序,依次对所有的数据进行上述操作,直到所有的数据都按照要求完成排序
 * 冒泡排序的特点:如果有n个数据,那么要比较n-1轮,每轮比较完毕后,下一轮就少比较一次,也就是说少一个数据参与比较
 * 冒泡排序性能优化版本
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-07 14:20
 * @since Java21
 */
public class BubbleSortOptimize {
    public static void main(String[] args) {
        System.out.println("******************优化版本数据升序冒泡排序实现******************");
        //① 准备测试数据
        //创建Scanner对象
        //System.in 标准输入,也就是键盘输入
        //Scanner对象可以扫描用户从键盘输入的数据
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入待排序整数的个数");
        int length = scanner.nextInt();
        System.out.println("请输入待排序的整数(每输完一个就回车)");
        //排序的数据有5个
        int[] array = new int[length];
        for (int i = 0; i < length; i++) {
            array[i] = scanner.nextInt();
        }

        //关闭Scanner
        scanner.close();


        //②冒泡排序优化版实现
        System.out.println("冒泡排序优化版【升序排序】之前数组的元素是" + Arrays.toString(array));
        //统计循环次数
        int totalCount = 0;
        int round = 0;
        //一共比较array.length-1轮,每轮比较确定一个数的位置,例如第一轮确定最大值的位置,第二轮确定第二大的值的位置,依此类推
        //外层循环控制排序的轮数
        for (int i = 0; i < array.length - 1; i++) {
            //标记思想:用于标识在一轮排序过程中是否有元素被交换
            boolean swapped = false;
            round++;
            int count = 0;
            //内层循环控制每轮比较的次数
            //每轮比较的次数逐渐减少 假如有5个数据,第一轮比较4次,第二轮比较3次,第三轮比较2次,第四轮比较1次
            for (int j = 0; j < array.length - 1 - i; j++) {
                totalCount++;
                count++;
                //比较相邻的两个整数,如果前面的数大于后面的数
                if (array[j] > array[j + 1]) {
                    //就交换位置
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    //本轮有元素交换
                    swapped = true;
                    System.out.printf("第%d轮 第%d次比较,数组的元素是%s\n", round, count, Arrays.toString(array));
                }
            }
            //检查 swapped 是否仍为 false,如果是,则表示没有发生交换,意味着数组已经是有序的,因此可以直接跳出循环。
            if (!swapped) {
                break;
            }
        }
        System.out.println("冒泡排序优化版【升序排序】之后数组的元素是" + Arrays.toString(array));
        System.out.println("总循环次数是" + totalCount);

    }

}

  1. 运行BubbleSortOptimize.java

程序运行结果

9.9 选择排序

9.9.1 选择排序介绍

选择排序(Selection Sort)是一种简单直观的比较排序算法。它的基本思想是在未排序序列中找到最小(或最大)的元素,存放到已排序序列的起始位置,然后再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

选择排序

9.9.2 选择排序基础版

  1. 编辑SelectionSort.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;
import java.util.Scanner;

/**
 * 9.9.2 选择排序基础版
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-07 11:36
 * @since Java21
 */
public class SelectionSort {
    public static void main(String[] args) {
        //① 准备测试数据
        //创建Scanner对象
        //System.in 标准输入,也就是键盘输入
        //Scanner对象可以扫描用户从键盘输入的数据
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入待排序整数的个数");
        int length = scanner.nextInt();
        System.out.println("请输入待排序的整数(每输完一个就回车)");
        //排序的数据有5个
        int[] array = new int[length];
        for (int i = 0; i < length; i++) {
            array[i] = scanner.nextInt();
        }
        //②选择排序实现
        System.out.println("选择排序基础版【升序排序】之前数组元素内容是" + Arrays.toString(array));
        int round = 0;
        //外层循环控制轮数
        //一共比较array.length-1轮
        //统计循环次数
        int totalCount = 0;
        for (int i = 0; i < array.length - 1; i++) {
            round++;
            int count = 0;
            //内层循环控制每轮比较的次数,每轮的比较的次数减少1次
            for (int j = i + 1; j < array.length; j++) {
                totalCount++;
                count++;
                System.out.printf("第%d轮 第%d次%d和%d比较,", round, count, array[i], array[j]);
                //array[i]和array[j]进行比较
                if (array[i] > array[j]) {
                    int temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }
                System.out.printf("比较之后数组的元素是%s\n", Arrays.toString(array));
            }
        }
        System.out.println("选择排序基础版【升序排序】之后数组元素内容是" + Arrays.toString(array));
        System.out.println("总循环次数是" + totalCount);

    }
}

  1. 运行SelectionSort.java

程序运行结果

9.2.3 选择排序优化版

在选择排序基础版基础上做以下优化

  1. 编辑SelectionSortOptimize.java
package net.ittimeline.java.core.array.algorithm;

import java.util.Arrays;
import java.util.Scanner;

/**
 * 9.9.3 选择排序优化版
 *
 * @author tony 18601767221@163.com
 * @version 2024-09-08 22:20
 * @since Java21
 */
public class SelectionSortOptimize {
    public static void main(String[] args) {
        //① 准备测试数据
        //创建Scanner对象
        //System.in 标准输入,也就是键盘输入
        //Scanner对象可以扫描用户从键盘输入的数据
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入待排序整数的个数");
        int length = scanner.nextInt();
        System.out.println("请输入待排序的整数(每输完一个就回车)");
        //排序的数据有5个
        int[] array = new int[length];
        for (int i = 0; i < length; i++) {
            array[i] = scanner.nextInt();
        }

        //关闭Scanner
        scanner.close();
        System.out.println("选择排序优化版【升序排序】之前数组元素内容是" + Arrays.toString(array));

        //② 选择排序优化版实现
        int round = 0;
        //统计循环次数
        int totalCount = 0;
        //外层循环控制轮数
        for (int i = 0; i < array.length - 1; i++) {
            round++;
            int count = 0;
            //标记思想:用于标识在一轮排序过程中是否有元素被交换
            boolean swapped = false;
            //内层循环控制每轮比较的次数,每轮比较的次数少一次
            for (int j = i + 1; j < array.length; j++) {
                totalCount++;
                count++;
                System.out.printf("第%d轮 第%d次%d和%d比较,", round, count, array[i], array[j]);
                if (array[i] > array[j]) {
                    int temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                    swapped = true;
                }
                System.out.printf("比较之后数组的元素是%s\n", Arrays.toString(array));

            }
            //检查 swapped 是否仍为 false,如果是,则表示没有发生交换,意味着数组已经是有序的,因此可以直接跳出循环。
            if (!swapped) {
                break;
            }
        }
        System.out.println("选择排序优化版【升序排序】之后数组元素内容是" + Arrays.toString(array));
        System.out.println("总循环次数是" + totalCount);

    }
}

  1. 运行SelectionSortOptimize.java

程序运行结果

提供典型应用案例,剖析JSP/Servret技术与Struts 2技术在Web开发中的不同 提供完整的应用案例,使读者可以深入体会SSH开发模式的精髓 所有开发工具和框架均使用目前的最新版本,紧跟技术发展的趋势 提供230个实例和4个综合案例,可以作为案头必备的查询手册 一线开发人员全力打造,分享技术盛宴! 重点内容及特色 《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》介绍了Web开发中客户端技术的基础知识,包括JavaScript、CSS、AJAX等,这些技术都是Web应用中常用的客户端技术。 《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax+》讲解了JSP/S rvlet技术的基础知识,并提供了一个综合案例展示其具体应用,它们是Java Web服务端技术的基石,也是Java Web开发所要必须掌握的技术。 《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》重点讲解了Struts 2、Speing和HIbernate框架的基础知识和高级技术,如Sruts 2中的*、类型转换、国际化和标签等,HIbe rna{e的会话、0/R映射和事务管理等,Spring中的数据库技术与AOP等。 《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》特别介绍了Struts 2对AjAX的支持,还重点剖析了SSH框架的整合开发,并给出了两个综合案例来展示整合SSH框架开发Web应用。 和已经出版的同类图书相比,《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》讲解由浅入深,涵盖更多内容,列举了大量典型实例具有超强的实用性,另外,《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》各篇独立,适合读者全面习或对部分内容重点习。 读者对象 有Java基础,想进一步习SSH框架整合开发的人员 了解SSH整合开发,想进一步提高开发技术的人员 正在使用SSH整合技术开发项目,想查阅资料的人员 大中专院校的生和老师,以及Java培训班的员和讲师 需要一本案头必备查询手册的程序员 光盘内容 6小时多媒体体视频讲解 《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》所涉及的源代码 布衣暖,菜根香,好书滋味长!清华大出版社长期以来一直秉承为读者多出好书的宗旨,多年来为读者奉献了大量脍炙人口的精品图书。尤其在计算机图书出版领域更是形成了鲜明特色,所出版的各类计算机图书受到了广大读者的好评。本次出版的“原创经典,程序员典藏”系列图书是清华大出版社的重点精品计算机图书,旨在帮助读者全面习各类程序设计语言开发工具,提高开发水平。同时也为广大程序员提供良好的技术参考,以便作为案头必备的查询手册。 内容提要 -------------------------------------------------------------------------------- 《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》通过对SSH中的各种技术循序渐进地讲解,使读者尽快掌握开发基于SSH的Web程序的方法。《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》内容包括Web客户端技术、JSP/Servlet技术、Struts 2(*、类型转换、输入校验、上传和下载文件、Struts 2的各种标签、对 AJAX的支持等)、Spring(Ioc容器、装配Java Bean、Jdbc和Hibernate模板、事务管理、Spring AOP等)以及 Hibernate(会话、映射、标准查询API、HQL、事务管理、锁等)。除此之外,《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》还提供了两个完整的实例来讲解开发SSH的详细步骤和方法。通过对这两个实例的习,读者可以对SSH开发模式有更透彻地理解和认识。SSH是目前最流行的Java Web开发技术。 《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》适合广大从事Java Web开发工作的技术人员、对SSH开发感兴趣的人员以及大专院校生阅读,尤其是具有一定的Web开发经验的技术人员。 目录 -------------------------------------------------------------------------------- 第1篇 web开发基础篇 第1 搭建开发环境 1.1 本书使用的软件和框架的版本 1.2 JDK6的下载与安装 1.3 Eclipse3.4 的下载与安装 1.4 MyEclipse6.5 的下载与安装 1.5 Eclipse:IDEforJavaEEDevelopers的下载与安装 1.6 Tomcat6的下载与安装 1.7 在MyEclipse中配置。Tomcat 1.8 在EclipseIDEforJavaEEDevelopers中配置Tomcat 1.9 小结 第2 JavaWeb应用开发基础 2.1 Web技术的发展 2.2 JavaWeb技术 2.2.1 Java.Welb程序的基本组成 2.2.2 Java,Web程序的目录结构 2.2.3 JavaWeb程序的配置文件 2.3 MVC模式与MvC框架 2.3.1 JSP模型1和JSP模型2 2.3.2 Web应用程序需要的基础服务 2.3.3 MVC模式概述 2.3.4 常用的MvC框架 2.4 小结 第3 Web开发中的客户端技术 3.1 常用的JavaScriptIDE简介 3.1.1 在MyEclipse中使用JavaScript 3.1.2 在EclipseIDEforJavaEE中使用JavaScript 3.1.3 在NetBeans中使用JavaScript 3.1.4 其他的JavaScriptIDE 3.2.1 avaScdpt语法基础 3.2.1 实例:编写第一个JavaScript程序:Greet 3.2.2 变量 3.2.3 原始类型 3.2.4 类型转换 3.2.5 函数与函数调用 3.2.6 类和对象 3.3 JavaScript高级技术 3.3.1 DOM技术概述 3.3.2 获得HTML元素的3种方法 3.3.3 实例:图像自动切换 3.3.4 正则表达式 3.3.5 实例:表格排序 3.4 CSS基础 3.4.1 CSS的基本语法 3.4.2 在Style属性中定义样式 3.4.3 在HTML中定义样式 3.4.4 在外部文件中定义样式 3.4.5 样式的继承 3.5 AJAX.基础 3.5.1 AJAX概述 3.5.2 实例:使用XMLHttpRequest获得Web资源 3.5.3 实例:使用XMLHttpRequest跨域访问Web资源 3.5.4 实例:AJAX的3种交换数据方法 3.6 小结 第4 Servlet技术 4.1 Servlet的Helloworld程序 4.1.1 实例:在My Eclipse中编写Helloworld程序 4.1.2 实例:手工编写:Helloworld程序 4.2 Servlet基础 4.2.1 配置数据库连接池 4.2.2 数据库连接池的应用 4.2 -3实例:用doGet方法处理客户端请求 4.2.4 实例:用doPost方法处理客户端请求 4.2.5 实例:用service方法处理客户端请求 4.2.6 实例:初始化(init)和销毁(destroy)Servlet 4.2.7 实例:使用PrintWriter输出响应消息 4.2.8 实例:用ServletOutputStream显示图像 4.2.9 实例:使用RequestDispatcher包含Web资源 4.2.10 实例:使用RequestDispatcher转发Web资源 4.3 HttpServletResponse类的其他功能 4.3.1 产生状态响应码 4.3.2 设置响应消息头 4.3.3 实例:验证响应头设置情况 4.4 使用:HttpServletRequest获得请求消息 4.4.1 获取请求行消息 4.4.2 获取网络连接消息 4.4.3 获取请求头消息 4.5 处理Cookie 4.5.1 什么是Cookie 4.5.2 Cookie类中的方法 4.5.3 实例:用Cookie读写客户端信息 4.5.4 实例:用Cookie读写复杂数据 4.6 处理Session 4.6.1 什么是Session 4.6.2 HttpSession接口中的方法 4.6.3 HttpServletRequest接口中的Session方法 4.6.4 实例:通过Cookie跟踪Session 4.6.5 实例:通过重写uRL跟踪Session 4.7 Web开发的中文问题 4.7.1 Java的编码原理 4.7.2 实例:解决输出中文乱码问题 4.7.3 实例:解决服务端程序读取中文请求消息的乱码问题 4.7.4 实例:用AJAX技术发送和接收中文信息 4.7.5 实例:在请求消息头和响应消息头中转输中文 4.8 小结 第5 JSP技术 5.1 用MyEclipse编写第一个JSP程序 5.1.1 实例:编写显示服务器当前时间的JSP程序 5.1.2 调试JSP程序 5.1.3 改变JSP的访问路径和扩展名 5.1.4 手动发布JSP程序 5.2 JSP的运行原理 5.2.1 Tomcat如何处理JSP页 5.2.2 分析由JSP生成的Servlet代码 5.3 JSP基本语法 5.3.1 JSP表达式 5.3.2 在JSP中嵌入Java代码 5.3.3.JSP声明 5.3.4.JSP表达式语言(EL) 5.3.5 实例:用EL函数替换HTML中的特殊字符 5.3.6 JSP页面中的注释 5.4 JSP指令 5.4.1 JSP指令简介 5.4.2 page页面指令 5.4.3 include加入指令 5.5.JSP的9个内置对象 5.5.1 out输出对象 5.5.2 pageContext封装对象 5.5.3 其他的JSP内置对象 5.6 JSP标签 5.6.1 插入标签 5.6.2 转发标签 5.6.3 传参标签 5.6.4 创建:Bean标签 5.6.5 设置属性值标签 5.6.6 获取属性值标签 5.7 JSP的标准标签库(JSTL) 5.7.1 如何使用JSTL 5.7.2 条件标签 5.7.3 循环标签 5.8 小结 第6 用Servlet和JSP实现注册登录系统 第2篇 Struts 2篇 第7 编写Struts 2的第一个程序 第8 Struts 2进阶 第9 Struts 2的* 第10 Struts 2的类型转换 第11 Struts 2的输入校验 第12 文件的上传和下载 第13 国际化 第14 Struts 2的标签库 第15 Struts 2对AJAX的支持 第16 用Struts 2实现注册登录系统 第3篇 Hibernate篇 第17 Hibernate的Helloworld程序 第18 配置Hibernate 第19 Hibernate的会话与O/R映射 第20 Hibernate的查询与更新技术 第21 Hibernate的高级技术 第4篇 Spring篇 第22 Spring的Helloworld程序 第23 反向控制(Ioc)与装配JavaBean 第24 Spring中的数据库技术 第25 Spring的其他高级技术 第5篇 综合实例篇 第26 Struts 2与Hibernate、Spring的整合 第27 网络硬盘 第28 论坛系统
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ittimeline

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值