05-数组

58 阅读15分钟

数组

1. 数组的概念

概念:一组连续的存储空间,存储多个相同数据类型的值,长度是固定的。

2. 数组的定义方式

先声明、再分配空间: 数据类型[] 数组名; 数组名 = new 数据类型[长度];

声明并分配空间: 数据类型[] 数组名 = new 数据类型[长度];

声明并赋值(繁): 数据类型[] 数组名 = new 数据类型[]{value1,value2,value3,...};

声明并赋值(简): 数据类型[] 数组名 = {value1,value2,value3,...};

中括号可以书写在数组名之后 但是推荐书写在类型之后 数组名之前

package com.xxx.test2;

/**
 * 数组的四种定义方式  中括号可以书写在数组名之后 但是推荐书写在类型之后 数组名之前
 * 1.先声明 再分配空间
 * 2.声明并且分配空间
 * 3.声明并且赋值(繁琐)
 * 4.声明并且赋值(简单)
 */
public class TestArrayDefine {
    public static void main(String args[]) {

        // 1.先声明 再分配空间
        int arr1[];
        arr1 = new int[3];

        // 2.声明并且分配空间
        int arr2[] = new int[4];


        // 3.声明并且赋值(繁琐) 这种方式可以分开写
        int arr3[] = new int[]{11, 23, 444, 666, 777, 234456};

        int  arr6[];
        arr6 = new int[]{12,3,4,5667,777};


        // 4.声明并且赋值(简单) 这种方式必须在一行书写完成 不能分开写

        int arr4[] = {1, 2, 33, 44, 567};

//        int [] arr5;
//        arr5 = {1,2,3,4,5};


    }
}

3. 数组的使用

数组的使用

元素:数组中的数据称之为元素 Element

下标:角标,索引,英文名称 index 从0开始 往后依次+1

访问 对元素进行存取的操作 称之为访问

取值:System.out.print(数组名[下标])

赋值:数组名[下标] = 值;

访问不存在的下标 会出现:数组下标越界异常 ArrayIndexOutOfBoundsException

异常会导致程序中断 即未执行的代码 不再执行

package com.xxx.test3;

/**
 *  数组的使用
 *      元素:数组中的数据称之为元素 Element
 *      下标:角标,索引,英文名称 index 从0开始 往后依次+1
 *      访问 对元素进行存取的操作 称之为访问
 *          取值:System.out.print(数组名[下标])
 *          赋值:数组名[下标] = 值;
 *
 *  访问不存在的下标 会出现:数组下标越界异常 ArrayIndexOutOfBoundsException
 *  异常会导致程序中断 即未执行的代码 不再执行 
 */
public class TestArrayUes {
    public static void main(String[] args) {
        int [] nums = new int[5];

        // 赋值
        nums[0] = 11;
        nums[1] = 433;
        nums[2] = 123;
        nums[3] = 444;
        nums[4] = 555;
//        nums[5] = 666;

        // 取值
        System.out.println("第一个元素的值为:" + nums[0]);
        System.out.println("第二个元素的值为:" + nums[1]);
        System.out.println("第三个元素的值为:" + nums[2]);
        System.out.println("第四个元素的值为:" + nums[3]);
        System.out.println("第五个元素的值为:" + nums[4]);
//        System.out.println("第六个元素的值为:" + nums[100]);

    }
}

4.数组的遍历

数组的遍历:逐一对数组中元素进行访问

数组的属性:length 是一个int类型的整数 表示数组元素的个数 也就是数组长度

可以通过数组名加点进行使用

数组名.length

JDK提供了关于获取数组元素信息的方法 :Arrays.toString(数组名)

这个方法会将数组中的元素 拼接为字符串 并且使用[]包括起来

package com.xxx.test3;

import java.util.Arrays;

/**
 *  数组的遍历:逐一对数组中元素进行访问
 *
 *  数组的属性:length 是一个int类型的整数 表示数组元素的个数 也就是数组长度
 *  可以通过数组名加点进行使用
 *  数组名.length
 *
 *  JDK提供了关于获取数组元素信息的方法 :Arrays.toString(数组名)
 *  这个方法会将数组中的元素 拼接为字符串 并且使用[]包括起来
 *
 *
 */
public class TestArrayForeach {
    public static void main(String[] args) {
        int [] nums = {11,55,88,65,32,789,444,555,1,2,3,555,666,77,888,34,213,24,345,765,243};

        System.out.println(nums.length);

        for(int i = 0;i < nums.length;i++){
            System.out.println("第" + (i + 1) + "个元素的值为:" + nums[i]);
        }

        String numsStr = Arrays.toString(nums);

        System.out.println("numsStr = " + numsStr);

        System.out.println("程序结束");

    }
}

5. 数组的默认值

数组的默认值

数组作为引用数据类型 其元素是有默认值的 当我们开辟空间以后 默认值即存在

整数:0

小数:0.0

字符:\u0000

布尔:false

其他:null

数组定义在方法内,是否属于局部变量?

依然属于局部变量 凡是定义在方法体内的(形参也是) 都属于局部变量

局部变量没有默认值,为什么数组有默认值呢?

局部变量是指只声明 没有赋值的变量没有默认值

而数组属于 我们赋值以后的默认值 开辟空间 以后的默认值

package com.xxx.test4;

import java.util.Arrays;

/**
     *  数组的默认值
     *  数组作为引用数据类型 其元素是有默认值的 当我们开辟空间以后 默认值即存在
     *      整数:0
     *      小数:0.0
     *      字符:\u0000
     *      布尔:false
     *      其他:null
     *
     *  数组定义在方法内,是否属于局部变量?
     *      依然属于局部变量 凡是定义在方法体内的(形参也是) 都属于局部变量
     *
     *  局部变量没有默认值,为什么数组有默认值呢?
     *      局部变量是指只声明 没有赋值的变量没有默认值
     *      而数组属于 我们赋值以后的默认值 开辟空间 以后的默认值
 *
 */
public class TestArrayDefaultValue {
    public static void main(String[] args) {

        byte [] a1 = new byte[3];

        for(int i = 0;i < a1.length ;i++){
            System.out.print(a1[i] + "\t");
        }
        System.out.println();

        short [] a2 = new short[4];
        // 打印方法表示打印方法的返回值
        System.out.println(Arrays.toString(a2));


        int [] a3 = new int[5];
        System.out.println(Arrays.toString(a3));

        long [] a4 = new long[6];
        System.out.println(Arrays.toString(a4));

        float [] a5 = new float[1];
        System.out.println(Arrays.toString(a5));

        double [] a6 = new double[2];
        System.out.println(Arrays.toString(a6));

        boolean [] a7 = new boolean[3];
        System.out.println(Arrays.toString(a7));

        char [] a8 = new char[4];
        System.out.println(Arrays.toString(a8));

        String [] a9 = new String[3];
        System.out.println(Arrays.toString(a9));


    }
}

6. 数组的扩容

数组的扩容

创建大于原数组长度的新数组。

将原数组中的元素依次复制到新数组中。

将新数组的地址赋值给指向老数组的变量。

package com.xxx.test5;

import java.util.Arrays;

/**
 *  数组的扩容
 *      创建大于原数组长度的新数组。
 *      将原数组中的元素依次复制到新数组中。
 *      将新数组的地址赋值给指向老数组的变量。
 */
public class TestArrayGrow {
    public static void main(String[] args) {
        int [] oldArray = {11,22,33,44,55};

        // 创建大于原数组长度的新数组。
        int [] newArray = new int[oldArray.length * 2];


        // 将原数组中的元素依次复制到新数组中。
        for(int i = 0;i < oldArray.length;i++){
            newArray[i] = oldArray[i];
        }

        System.out.println(Arrays.toString(oldArray));
        System.out.println(Arrays.toString(newArray));

        System.out.println("赋值地址之前原数组的地址:" + oldArray);
        System.out.println("赋值地址之前新数组的地址:" + newArray);


        // 数组作为引用数据类型 其数组名中保存的是指向堆中的地址值
        // 所以 将一个数组赋值给另外一个数组 赋值的是堆中的地址
         oldArray = newArray;

        System.out.println(oldArray.length);
        System.out.println(newArray.length);

        System.out.println("赋值地址之后原数组的地址:" + oldArray);
        System.out.println("赋值地址之后新数组的地址:" + newArray);


    }
}

7. 复制数组的方式

复制数组的三种方式

​ 循环将原数组中所有元素逐一赋值给新数组。

​ System.arraycopy(原数组,原数组起始,新数组,新数组起始,长度);

​ java.util.Arrays.copyOf(原数组, 新长度);//返回带有原值的新数组。

package com.xxx.test5;

import java.util.Arrays;

/**
 *  复制数组的三种方式
 *      循环将原数组中所有元素逐一赋值给新数组。
 *      System.arraycopy(原数组,原数组起始,新数组,新数组起始,长度);
 *      java.util.Arrays.copyOf(原数组, 新长度);//返回带有原值的新数组。
 */
public class TestArrayCopy {
    public static void main(String[] args) {
        int [] arr1 = new int[]{1,2,3,4,5};

        int [] arr2 = new int[10];
		// 第一个参数 原数组
        // 第二个参数 新数组
        // 第三个参数 原数组起始位置 0表示第一个 
        // 第四个参数 新数组起始位置 0表示第一个 
        // 第五个参数 复制元素的个数
        System.arraycopy(arr1,0,arr2,5,5);

        System.out.println(Arrays.toString(arr2));

        System.out.println("-----------------------------------------");

        int [] nums = {12,23,34,45,56};

        // 第一个参数  原数组
        // 第二个参数  新长度   此方法会返回一个新的数组 
        int [] newNums =  Arrays.copyOf(nums,10);

        System.out.println(Arrays.toString(newNums));





    }
}

8. 数组练习题

统计int类型数组中所有元素的总和,平均值。

package com.xxx.test5;

import java.util.Scanner;

/**
 *  统计int类型数组中所有元素的总和/平均值。
 *
 *  数组名.for 增强for循环
 *  数组名.fori  普通for循环 从前往后遍历
 *  数组名.forr 普通for循环 从后往前遍历
 *
 */
public class TestArrayExercise1 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入一个数组长度");
        int length = input.nextInt();
        int [] nums = new int[length];
        for(int i = 0; i < nums.length; i++){
            System.out.println("请输入数组中的第" + (i + 1) + "个元素的值");
            nums[i] = input.nextInt();
        }
        System.out.println("--------------------------------------------------------");
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
        }
        System.out.println("总和为:" + sum);
        System.out.println("平均值为:" + sum / nums.length);
    }
}

9. 数组类型的参数和返回值

数组类型的参数 和 返回值 :使用方式与之前相同

需求:

1.编写方法用于统计一个学生的5门成绩 使用数组作为返回值返回5门成绩

2.编写方法用于计算一个学生5门成绩的平均分

package com.xxx.test6;

import java.util.Scanner;

/**
 *  数组类型的参数 和  返回值 :使用方式与之前相同
 *
 *  需求:
 *      1.编写方法用于统计一个学生的5门成绩 使用数组作为返回值返回5门成绩
 *      2.编写方法用于计算一个学生5门成绩的平均分
 */
public class TestArrayParamAndReturnedValue {
    public static double[] inputScores(){
        Scanner input = new Scanner(System.in);
        double [] scores = new double[5];
        for(int i = 0;i < scores.length;i++){
            System.out.println("请输入第" + (i + 1) + "门成绩");
            scores[i] = input.nextDouble();
        }
        return scores;
    }

    public static void printScoresAvg(double [] scores){
        double sum = 0;
        for (int i = 0; i < scores.length; i++) {
            sum += scores[i];
        }
        System.out.println("平均分为:" + sum / scores.length);
    }
    public static void main(String[] args) {
        double [] score = inputScores();
        printScoresAvg(score);
    }

}

10.可变长参数

概念:可变长参数 可接收多个同类型实参,个数不限,使用方式与数组相同。

语法:数据类型... 形参名

要求:必须定义在形参列表的最后,且只能有一个。

package com.xxx.test6;

/**
 *  概念:可变长参数  可接收多个同类型实参,个数不限,使用方式与数组相同。
 *  语法:数据类型... 形参名
 *  要求:必须定义在形参列表的最后,且只能有一个。
 */
public class TestChangeableParam {
    public static void m1(int [] arr1){
        System.out.println("m1方法开始执行");
        for (int i = 0; i < arr1.length; i++) {
            System.out.println(arr1[i]);
        }
        System.out.println("m1方法开始执行");
    }

    public static void m2(int a, int... arr1){
        System.out.println("m2方法开始执行");
        for (int i = 0; i < arr1.length; i++) {
            System.out.println(arr1[i]);
        }
        System.out.println("m2方法执行完毕");
    }

    public static void main(String[] args) {
        int [] arr1 = {};
        m1(arr1);

        m2(1,11,333,444);


    }


}

11. 值传递和引用传递的区别

数组面试题 : 值传递和引用传递的区别 ?

基本数据类型传参 传递的是值的副本(拷贝) 属于将值复制了一份 传给了形参 称之为值传递

引用数据类型传参 传递的是内存中的地址值 属于引用(地址值)传递

Java官方明确说明 Java中是没有所谓的 “引用传递” 只有值传递

package com.xxx.test6;

import java.util.Arrays;

/**
 *  数组面试题 : 值传递和引用传递的区别 ?
 *
 *  基本数据类型传参 传递的是值的副本(拷贝) 属于将值复制了一份 传给了形参  称之为值传递
 *
 *  引用数据类型传参 传递的是内存中的地址值 属于引用(地址值)传递
 *
 *  Java官方明确说明 Java中是没有所谓的 “引用传递”  只有值传递
 */
public class TestArrayInterview {

    public static void m1(int num){
        num++;
        System.out.println("num = " + num); // 11
    }

    public static void m2(int [] nums){
        System.out.println("nums = " + nums);
        for (int i = 0; i < nums.length; i++) {
            nums[i] = 666;
        }
        System.out.println("nums = " + Arrays.toString(nums));
    }
    public static void main(String[] args) {
        int a = 10;
        m1(a);
        System.out.println("a = " + a); // 10

        int [] arr = {1,2,3,4,5};
        System.out.println("arr = " + arr);
        m2(arr);
        System.out.println("arr = " + Arrays.toString(arr));
    }
}

12. 冒泡排序

冒泡排序

外层循环 行 比较的轮数:n - 1

内层循环 列 每一轮比较的次数 : n - 1 - i

package com.xxx.test7;

import java.util.Arrays;

/**
 *  冒泡排序
 *      外层循环   行   比较的轮数:n - 1
 *      内层循环   列   每一轮比较的次数 : n - 1 - i
 */
public class TestBubbleSort {
    public static void main(String[] args) {
        int [] nums = {5,4,3,2,1,0};

        for(int i = 0;i < nums.length - 1;i++){
           
            for(int j = 0;j < nums.length - 1 - i;j++){
                if(nums[j] < nums[j + 1]){
                    flag = false;
                    int temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;
                }
            }
            System.out.println("第" + (i + 1) + "轮比较完成以后元素的顺序为:" + Arrays.toString(nums));
        }

        System.out.println(Arrays.toString(nums));

    }
}

13.冒泡排序优化

因为冒泡排序 如果顺序不正确 则会立即交换元素的位置

所以 如果本轮没有交换元素的位置 则可以判定为 元素已经排列正确

则可以提前结束循环

package com.xxx.test7;

import java.util.Arrays;

/**
 *  冒泡排序
 *      外层循环   行   比较的轮数:n - 1
 *      内层循环   列   每一轮比较的次数 : n - 1 - i
 */
public class TestBubbleSort {
    public static void main(String[] args) {
        int [] nums = {5,4,3,2,1,0};

        for(int i = 0;i < nums.length - 1;i++){
            boolean flag = true; // 每一轮开始 表示初始值都为true 
            for(int j = 0;j < nums.length - 1 - i;j++){
                if(nums[j] < nums[j + 1]){
                    flag = false;
                    int temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;
                }
            }

            System.out.println("第" + (i + 1) + "轮比较完成以后元素的顺序为:" + Arrays.toString(nums));

            if(flag){ // 本轮比较完成 标记依然为true 则表示本轮未交换任何元素的位置 
                break; // 则表示可以直接结束循环 即后续的轮次不用比较了 
            }

        }

        System.out.println(Arrays.toString(nums));

    }
}

14. 选择排序

选择排序2.gif

选择排序 : 固定(位置)元素与其他元素依次比较大小,遇到需要交换位置的元素,

不立即交换位置,使用新的元素继续往后比较,等待一轮比较完成,交换一次位置。

选择排序我们可以理解为两个元素进行比较 假设为 A 和 B

元素A 从第一个位置开始 直到倒数第二个 位置 A 0 ~ n - 1

元素B 从A元素之后相邻的位置开始 直到最后一个 位置 B A + 1 ~ n

可以用外层循环 表示元素A

内存循环表示 元素B

package com.xxx.test1;

import java.util.Arrays;

/**
 *  选择排序  : 固定(位置)元素与其他元素依次比较大小,遇到需要交换位置的元素,
 *  不立即交换位置,使用新的元素继续往后比较,等待一轮比较完成,交换一次位置。
 *
 *
 *  选择排序我们可以理解为两个元素进行比较 假设为 A  和 B
 *  元素A 从第一个位置开始 直到倒数第二个 位置          A  0 ~ n - 1
 *  元素B 从A元素之后相邻的位置开始 直到最后一个 位置    B  A + 1 ~  n
 *
 *  可以用外层循环 表示元素A
 *  内存循环表示 元素B
 *
 *
 *
 *
 */
public class TestSelectionSort {
    public static void main(String[] args) {
        int [] nums = {-1,11,32,4,56,777,86,234};

        for(int a = 0;a < nums.length - 1;a++){
            int index = a; // 每次开始一轮新的比较 将当前元素a的下标 记录下来 赋值给index
            for(int b = a + 1 ;b < nums.length ;b++){
                if(nums[index] > nums[b]){
                    index = b;
                }

            }
            if(a != index){
                int temp = nums[a];
                nums[a] = nums[index];
                nums[index] = temp;
            }
            System.out.println("第" + (a + 1) + "轮比较完成以后元素的顺序为:" + Arrays.toString(nums));
        }


        System.out.println(Arrays.toString(nums));

    }
}

15. JDK提供的快速排序

JDK提供的快速排序:Arrays.sort() 升序

package com.xxx.test1;

import java.util.Arrays;

/**
 *  JDK提供的快速排序:Arrays.sort() 升序
 */
public class TestArraysSort {
    public static void main(String[] args) {
        int [] nums = {-1,11,32,4,56,777,86,234};

        Arrays.sort(nums);

        System.out.println(Arrays.toString(nums));


        System.out.println("*********************将升序改为降序方式1*********************");

        int [] arr1 = new int[nums.length];

        for(int i = 0,j = nums.length - 1;i < nums.length;i++,j--){
            arr1[j] = nums[i];
        }

        System.out.println(Arrays.toString(arr1));


        System.out.println("*********************将升序改为降序方式2*********************");


        for(int i = 0; i < nums.length / 2;i++){
            int temp = nums[i];
            nums[i] = nums[nums.length - 1 - i];
            nums[nums.length - 1 - i] = temp;
        }

        System.out.println(Arrays.toString(nums));



    }
}

16. 复杂度

算法复杂度.png

17. 二维数组

概念:一维数组中的一维数组;数组中的元素,还是数组。

package com.xxx.test2;

/**
 *  二维数组  :数组中的元素还是数组
 */
public class Test2DArray1 {
    public static void main(String[] args) {
        int [] arr1 = {1,2,3,4};

        int [][] arr2 = {{11,22}  ,  {123,345,567,777}  , {22,55,88} };

        System.out.println(arr2[0]);
        System.out.println(arr2[0][0]);
        System.out.println(arr2[0][1]);


        System.out.println(arr2[1]);
        System.out.println(arr2[1][0]);
        System.out.println(arr2[1][1]);
        System.out.println(arr2[1][2]);
        System.out.println(arr2[1][3]);


        System.out.println(arr2[2]);
        System.out.println(arr2[2][0]);
        System.out.println(arr2[2][1]);
        System.out.println(arr2[2][2]);

        System.out.println("----------------------------------------");

        for(int i = 0;i < arr2.length;i++){
            for(int j = 0;j < arr2[i].length;j++){
                System.out.print(arr2[i][j]+ "\t");
            }
            System.out.println();
        }


    }
}

二维数组的创建

创建二维数组,高维度(第一个中括号)的长度必须直接书写,低维度(第二个中括号)的长度可以直接书写,也可以分开书写。

数组的默认值问题:

对于二维数组,其每个元素为一维数组,所以默认值为null

所以必须先开辟一维数组的空间 才可以存放数据 否则将出现空指针异常

NullPointerException NPE

package com.xxx.test2;

/**
 *  二维数组的创建
 *  创建二维数组,高维度(第一个中括号)的长度必须直接书写,低维度(第二个中括号)的长度可以直接书写,也可以分开书写。
 *
 *  数组的默认值问题:
 *
 *  对于二维数组,其每个元素为一维数组,所以默认值为null
 *  所以必须先开辟一维数组的空间 才可以存放数据 否则将出现空指针异常
 *  NullPointerException  NPE
 *
 *
 */
public class Test2DArray2 {
    public static void main(String[] args) {

        int [] nums = new int[3];

       // 方式1 先声明  再分配空间
        int [][] arr1;
        arr1 = new int[4][];

        System.out.println(arr1[0]);

        arr1[0] = new int[2];
        arr1[0][0] = 11;
        arr1[0][1] = 12;

        System.out.println(arr1[1]);
        arr1[1] = new int[]{11,22,33,44};


        System.out.println(arr1[2]);

        int [] array = {1,2,3,4,5};
        arr1[2] = array;


        System.out.println(arr1[3]);
        arr1[3] = new int[]{1,2,3,4,5};



        // 方式2 声明并且分配空间
        int [][] arr2 = new int[2][3];


        // 方式3 声明并且赋值 繁琐的方式
        int [][] arr3 = new int[][]{{11,22},{123,345,567,666},{1,2,3,4,5}};

        // 方式4 声明并且赋值 简单的方式
        int [][] arr4 = {{11,22},{123,345,567,666},{1,2,3,4,5}};
    }
}

18. 使用二维数组打印杨辉三角(可选)