【一篇理论、实操文章带你玩明白数组、冒泡排序】内含基础知识:数组的定义、创建、使用及数组工具类。及进阶知识:多维数组、冒泡排序、稀疏数组等,及Java的内存分析。详细讲解、扩展,总结笔记(萌新友好版)

一、数组的定义、创建及Java内存分析

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

声明的时候数组并不存在,只有在创建的时候才会存在,因此定义数组的时候一定要初始数组大小(长度)。

在这里插入图片描述

public class Demo01 {
    // 变量的类型    变量的名字  =  变量的值;

    public static void main(String[] args) {
        int[] nums;  // 1.声明一个数组
        int nums2[];  // 不建议这样书写

        nums = new int[10];  // 2.创建一个数组
        int[] num3 = new int[10];  // 必须初始数组大小。声明 + 创建

        // 3.给数组元素赋值
        nums[0] = 1;
        nums[1] = 2;
        nums[2] = 3;
        nums[3] = 4;
        nums[4] = 5;
        nums[5] = 6;
        nums[6] = 7;
        nums[7] = 8;
        nums[8] = 9;
        nums[9] = 10;
        System.out.println(nums[9]);  // 10
        System.out.println(nums.length);  //10

        // 计算所有元素的和
        int sum = 0;
        for (int i = 0; i < nums.length; i ++){  // 获取数组长度:arrays.length
            sum = sum + nums[i];
        }
        System.out.println("总和为:" + sum);  // 55
    }
}

二、数值的初始化

在这里插入图片描述

public class Demo02 {
    public static void main(String[] args) {
        // 静态初始化:创建 + 赋值
        int[] a = {1,2,3,4,5};  // 定义后a的数组数量不可改变
        System.out.println(a[0]);  // 1

        // 动态初始化:包含默认初始化。声明 + 初始化(创建空间)
        int[] b = new int[10];  // 数组b中的10个元素的值当前为默认值int类型的0。
        b[0] = 10;
        b[1] = 10;
        System.out.println(b[0]);  // 10
        System.out.println(b[1]);
        System.out.println(b[2]);  // 0
        System.out.println(b[3]);  // 0
    }
}

在这里插入图片描述

数组常用的使用方法:

public class Demo03 {
    public static void main(String[] args) {
        int[] arrays = {1,2,3,4,5};

        // 打印全部数组元素
        for (int i = 0; i < arrays.length; i++){
            System.out.println(arrays[i]);
        }
        System.out.println("=====================");

        // 计算所有元素的和
        int sum = 0;
        for (int i = 0; i < arrays.length; i ++){
            sum  += arrays[i];
        }
        System.out.println("sum=" + sum);
        System.out.println("======================");

        // 查找最大元素
        int max = arrays[0];
        for (int i = 1; i < arrays.length; i ++){
            if (arrays[i] > max){
                max = arrays[i];
            }
        }
        System.out.println("max=" + max);
    }
}

在这里插入图片描述

三、数组的使用

在这里插入图片描述

在这里插入图片描述

For - Each循环:

public class Demo04 {
    public static void main(String[] args) {
        int[] arrays = {1,2,3,4,5};

        // JDK1.5以上。
        // 遍历数组中的每个元素。【没有下标】
        for (int array : arrays) {  // For- Each循环。遍历arrays数组中的每个元素
            System.out.println(array);
        }
    }
}

数组作方法入参:

public class Demo004 {
    public static void main(String[] args) {
        int[] arrays = {1,2,3,4,5};

        printArray(arrays);
    }
    // 打印数组元素
    public static void printArray(int[] array){  // 数组作方法入参
        for (int i = 0; i < array.length; i ++){
            System.out.print(array[i] + " ");
        }
    }
}

数组作返回值:

public class Demo0004 {
    public static void main(String[] args) {
        int[] arrays = {1, 2, 3, 4, 5};
        int[] a = arrays;
        
		【重点:】
           Java,数组是引用类型。将一个数组变量直接赋值给另一个数组变量时。实际上是复制引用,使两个变量都指向同一个数组。
           数组的实际存储(数组元素)是在堆内存中,而数组的变量存储是在栈内存中,变量存储的是数组的引用(内存地址)。
           因此两个数组间的直接赋值其实是在复制数组的引用。当指向的数组元素改变时,两个变量都会受影响。
           而在使用方法返回新数组时,是将新数组的引用地址复制给了接收的数组。因此原数组的改变不会影响到接收的数组。
         
        int[] reverse = reverse(arrays);
        printArray(reverse);
    }

    // 反转数组
    public static int[] reverse(int[] array){  // 数组作返回值
        int[] result = new int[array.length];

        // 反转操作:
        for (int i = 0, j = result.length - 1; i < array.length; i++, j--) {
            result[j] = array[i];
        }
        return result;
    }
    // 打印数组元素
    public static void printArray(int[] array){
        for (int i = 0; i < array.length; i ++){
            System.out.print(array[i] + " ");
        }
        System.out.println();
    }
}

四、多维数组

在这里插入图片描述

简单的说就相当于数组的嵌套。

在这里插入图片描述

在这里插入图片描述

public class Demo05 {
    public static void main(String[] args) {

        // [4][2],类似于一个4行2列的数组

        /*
            1,2     array[0]
            2,3     array[1]
            3,4     array[2]
            4,5     array[3]
         */
        int[][] array = { {1,2}, {2,3}, {3,4}, {4,5} };

        System.out.println(array[0]);  // 输出:[I@ed17bee。输出{1,2}这个对象的hashCode。

        printArray(array[0]);  // 传入{1,2}这个一维数组。会输出1和2,中间换行。
        System.out.println(array[0][0]);  // 1
        System.out.println(array[0][1]);  // 2
        System.out.println(array.length);  // 4
        System.out.println(array[0].length);  // 2
        System.out.println("=====================");

        // 打印二维数组中的每个具体元素
        for (int i = 0; i < array.length; i++) {  // 遍历二维数组中的一维数组对象
            for (int j = 0; j < array[i].length; j++) {  // 遍历二维数中一维数组对象的元素
                System.out.println(array[i][j]);
            }
        }
        // 如下:使用增强for循环遍历并打印二维数组中的元素
        for (int[] object : array) {  // 遍历二维数组的一维数组对象
            for (int value : object) {  // 遍历一维数组对象中的元素
                System.out.print(value + "\t");
            }
        }
    }
    // 打印数组元素
    public static void printArray(int[] array){
        for (int i = 0; i < array.length; i ++){
            System.out.println(array[i]);
        }
    }
}

下面是输出一个三维数组:

public class Demo005 {
    public static void main(String[] args) {
        int[][][] array = { { {1,2}, {1,2,3} } ,{ {1,2,3}, {2,3,4}} ,{ {1,2}, {3,1} ,{4,3} ,{3,4,5} }};
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                for (int k = 0; k < array[i][j].length; k++) {
                    System.out.print(array[i][j][k] + "\t");  // 输出每一个具体的一维数组元素,用TAB键(制表符)间隔。
                }
            }
            System.out.println();  // 输出完一个二维数组换行。
        }
    }
}

五、数组的工具Arrays类

在这里插入图片描述

用Arrays类的,toString()方法打印数组元素:

import java.util.Arrays;

public class Demo06 {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,9090,13131,534,45,23};
        int[][] b = {{1,2,3},{2,3,4},{4,7}};

        // 打印数组元素Arrays.toString(array)。
        System.out.println(Arrays.toString(a));  // 输出:[1, 2, 3, 4, 9090, 13131, 534, 45, 23]
        printArray(a);
        System.out.println(Arrays.toString(b));  // 输出二维数组b中0、1、2的三个一维数组元素的对象。
        System.out.println(Arrays.deepToString(b));  // 输出:[[1, 2, 3], [2, 3, 4], [4, 7]]。Arrays.deepToString(array)打印二维数组元素。
    }
    public static void printArray(int[] a){  // 按照Arrays.toString()方法格式打印一维数组元素。
        for (int i = 0; i < a.length; i++) {
            if (i == 0){
                System.out.print("[");
            }
            if (i == (a.length - 1)){
                System.out.println(a[i] + "]");
            }else {
                System.out.print(a[i] + " ,");
            }
        }
    }
}

Arrays.sort(array):数组排序。
Arrays.fill(array,value):数组元素赋值。

import java.util.Arrays;

public class Demo006 {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,9090,13131,534,45,23};
        int[][] c = {{1,23,4},{1,3},{4}};

        // 数组进行排序:升序
        Arrays.sort(a);  // 默认只适用于一维数组。
        System.out.println(Arrays.toString(a));  // 输出:[1, 2, 3, 4, 23, 45, 534, 9090, 13131]

        // fill,默认只适用于一维数组
        Arrays.fill(a,val:0);  // 数组填充。这里是将0的值赋值给数组a的所有元素。
        System.out.println(Arrays.toString(a));  // 输出:[0, 0, 0, 0, 0, 0, 0, 0, 0]
        
        Arrays.fill(a,fromlndex:2,tolndex:4,val:0);
        // 数组填充。2为fromlndex(起始索引)、4为tolndex(结束索引)。将数值0赋值给下标2到下标4之前的元素(这里是下标2、下标3)。
        System.out.println(Arrays.toString(a));
        
// 扩展:遍历二维数组c中的一维数组
        for (int[] row:c){
            Arrays.fill(row,0);  // 将0赋值给二维数组c中一维数组的每个元素。Arrays.fill(int[] a, int val):将指定的int值val填充到整个int[]数组a的所有元素中。
        }
        System.out.println(Arrays.deepToString(c));  // 输出:[[0, 0, 0], [0, 0], [0]]
    }
}

Arrays.equals(array1,array2):判断两个数组是否相等。返回布尔值。
Arrays.binarysearch(array,key):查找【已排序的】数组元素(key)。返回索引下标。

import java.util.Arrays;

public class Demo00006 {
    public static void main(String[] args) {
        int[] a = {1,2,3};
        int[] b = {1,2,3};
        int[] c = {2,1,3,3};
        int[][] x = {{1,1},{2,3}};
        int[][] y = {{1,1},{2,3}};
        int[][] z = x;

        // Arrays.equals()方法用于比较两个数组是否完全相同(值、顺序、数量、类型均相同)。返回值为布尔类型。
        boolean d = Arrays.equals(a ,b);
        System.out.println(d);  // true
        boolean e = Arrays.equals(a ,c);
        System.out.println(e);  // false

        boolean f = Arrays.equals(x,y);  // Arrays.equals()方法对于多维数组比较的是每个子数组的引用(内存地址)。
        System.out.println(f);  // false。因为数组x和y的子数组内存地址不同。
        boolean g = Arrays.equals(x,z);
        System.out.println(g);  // true

 【注意点:】
          Arrays.binarySearch(array,key)Java提供的二分查找方法,用于在【已升序排序的数组】中查找指定元素key。
          如果找到,返回该元素的索引(下标)(0开始)。如果没找到,返回一个 -(插入点 + 1)。插入点就是按照数组排序,应该插入的位置下标。
          如果在一个升序排序的数组里面,有多个相同元素,binarySearch无法保证返回第一个或最后一个,只保证返回其中一个的索引。
          数组必须是升序排列的,否则结果不可靠。
         
        // Arrays.binarySearch(a,key:3):查找数组a里面键为3的索引(下标)。默认只支持一维数组的查找。
        int result = Arrays.binarySearch(a,3);
        System.out.println(result);  // 2
        int result1 = Arrays.binarySearch(a,23);
        System.out.println(result1);  // -4。-4 = -(插入点:3 + 1)。插入点就是按照数组排序,应该插入的位置下标。
        int result2 = Arrays.binarySearch(c,2);
        System.out.println(result2);  // -3。因为数组c不是升序列表,所以结果不可靠。
        int result3 = Arrays.binarySearch(c,3);
        System.out.println(result3); // 2
        Arrays.sort(c);
        int result4 = Arrays.binarySearch(c,3);
        System.out.println(result4);  // 2
    }
}

以下是查看Arrays类的任意方法的源码小技巧:

在这里插入图片描述

在这里插入图片描述

六、冒泡排序

在这里插入图片描述

在这里插入图片描述

将变量1的值先赋予给中间变量,然后将变量2的值赋值给变量1(此时为变量2的值)。最后将中间变量的值(原先变量1的值)赋予变量2(此时为原先变量1的值),这样就完成了两个变量值的交换。

下面是一个比较标准的冒泡排序:

import java.util.Arrays;

public class Demo07 {
    public static void main(String[] args) {
        int[] a = {1,7,5,6,72,2,2,2,25,6,7};
        int[] sort = sort(a);
        System.out.println(Arrays.toString(sort));
    }
    /*
    冒泡排序:
       1.比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置。
       2.每一次比较,都会产生出一个最大,或者最小的数。
       3.下一轮则,少一次排序。
       4.依次循环,直到结束。
     */
    public static int[] sort(int[] array){
        int temp = 0;  // 临时变量

        // 外层循环,判断要走多少次循环
        for (int i = 0; i < array.length - 1; i++) {

            boolean flag = false;  // 通过flag标识位减少没有意义的比较

            // 内层循环,比较两个数,如果第一个数,比第二个数大,则交换位置
            for (int j = 0; j < array.length - 1 - i; j++) {
                if (array[j] > array[j+1]){  // 改变判断符号为: <。将改变排序顺序为降序
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                    flag = true;  // 当某一次内层循环的比较都不成立时,代表已经排序完毕。因此标识位flag不会被赋予true值。就会运行到下面的判断,然后结束整个循环。
                }
  【运行详细分析:】
               先是将array[0]和array[1]比较,决定是否交换位置。
               然后将array[1]和array[2]比较,决定是否交换位置。
               依次遍历,到array[j]和array[j+1]比较时,产生的结果将是数组中当前遍历的最大的数,并交换到最右边。
               理论逻辑:如果array[0]就是数组中当前最大的数,那么第一次比较,这个最大的数会被交换到array[1]的位置,
               第二次比较则是对array[1]和array[2]的比较,那么又会被交换到array[2]的位置。如果array[0]是最大的数,那么每一次遍历比较的时候都会有它,因为每一次比较它都会被往右移动。
               直到array[0]被移动到最右边,这样就完成了一次完整的内循环。
               因此完成一次内循环,产生的结果是,当前遍历中最大的数会被移动到最右边。
    
  【核心逻辑:内层循环完成一次完整的遍历时,就会将当前遍历中最大的数移动到最右边,然后外层循环i+1,因此内层循环减少一次遍历(就是减少了对最右边排好了的一次遍历)}
            if (flag == false){
                break;  // break语句只会跳出当前所在的循环(即直接包含它的那一层循环),并不会跳出外层循环。
            }
        }
        return array;
    }
}

以下是冒泡排序的精简核心代码,和关于循环的判断条件的核心解释:

import java.util.Arrays;

public class Demo007 {
    public static void main(String[] args) {
        int[] array = {234,15,7686,32,9,3,1,970,3,7};
        sort(array);  // 方法的返回值可以不被接收,编译器不会报错。Java允许忽略返回值。
        System.out.println(Arrays.toString(array));  // Arrays.toString()方法只返回一个字符串,如返回"[1,2,3]"。它本身并不会打印输出,所以要配合输出语句输出。

        String a = Arrays.toString(array);
        System.out.println(a);  // 输出:[1, 3, 3, 7, 9, 15, 32, 234, 970, 7686]
    }
    public static int[] sort(int[] arrays){  // 数组是引用类型,方法参数传递的是数组的引用地址。因此在方法内部改变数组,实参也会受影响。
        for (int i = 0; i < arrays.length -1; i++) {  // 数组元素的下标是从[0]到[length-1]。需要比较的下标j是从[0]到[length-2],即[0]到[length-2]就是外循环的次数。
            for (int j = 0; j < arrays.length -1 -i; j++) {  // 因为判断是arrays[j]和arrays[j+1]的比较,因此在[j=length-2]时就是在和[length-1]比较。
                if (arrays[j] > arrays[j+1]){  // i就是最外层的循环数,也是最右边已排序的元素个数(即内层完整的循环数)。因此减i就是避免遍历已经排序了的元素,并且不断缩小遍历范围,以此来达到循环的结束。
                    int temp = arrays[j];
                    arrays[j] = arrays[j+1];
                    arrays[j+1] = temp;
                }
            }
        }
        return arrays;
    }
}

七、稀疏数组

在这里插入图片描述

在这里插入图片描述

代码如下:使用稀疏数组记录五子棋棋盘

public class Demo08 {
    public static void main(String[] args) {
        // 1.创建一个二维数组  11 * 11    0:表示没有棋子。 1:表示黑棋。 2:表示白棋。
        int[][] array1 = new int[11][11];
        array1[1][2] = 1;
        array1[2][3] = 2;
        // 输出原始的数组
        System.out.println("输出原始的数组");
        for (int[] object : array1) {  // 遍历array1中的一维数组
            for (int value : object) {  // 遍历array1中一维数组的每个元素。二维数组中每个一维数组相当于是一行。
                System.out.print(value + "\t");  // 制表符隔开每个一维数组中的元素
            }
            System.out.println();  // 输出完一行(一维数组),换行。
        }
        // 2.转换为稀疏数组保存
        // 2.1 获取有效值的个数
        int sum = 0;
        for (int i = 0; i < 11; i++) {  // 行和列的下标:从0到10
            for (int j = 0; j < 11; j++) {
                if (array1[i][j] != 0){
                    sum++ ;
                }
            }
        }
        System.out.println("有效值的个数:" + sum);
        // 2.2创建一个稀疏数组
        int[][] array2 = new int[sum+1][3];  // 行:为有效值+1,因为第1行记录着原数组的总行、总列、有效值总个数。列为固定3,3列分别记录着:行、列、值
        array2[0][0] = 11;
        array2[0][1] = 11;
        array2[0][2] = sum;
        // 遍历二维数组,将非零的值,存放到稀疏数组中
        int count = 0;  // 计数
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                if (array1[i][j] != 0){
                    count ++;
                    array2[count][0] = i;
                    array2[count][1] = j;
                    array2[count][2] = array1[i][j];
                }
            }
        }
        // 输出稀疏数组
        System.out.println("稀疏数组");
        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i][0] + "\t"
                             + array2[i][1] + "\t"
                             + array2[i][2] + "\t");
        }
        // 3.还原
        // 3.1.读取稀疏数组
        int[][] array3 = new int[array2[0][0]][array2[0][1]];
        // 3.2.给其中的元素还原它的值
        for (int i = 1; i < array2.length; i++) {
            array3[array2[i][0]][array2[i][1]] = array2[i][2];
        }
        // 3.3.打印
        System.out.println("还原的数组");
        for (int[] object : array3) {
            for (int value : object) {
                System.out.print(value + "\t");
            }
            System.out.println();
        }
    }
}

以下是稀疏数组的精简核心代码,和核心解释:

public class Demo008 {
    public static void main(String[] args) {
        // 1.创建原始数组
        int[][] array1 = new int[11][11];  // 11行11列。代表着一共11个一维数组对象,每个一维数组对象有11个元素。
        array1[1][2] = 1;
        array1[2][3] = 2;

        // 2.创建稀疏数组
            /* 稀疏数组示例:
              行\列  [0]  [1]   [2]
              ------------------------
               [0]  总行  总列   总个数
               [1]  行1   列1    值1      【稀疏数组中除第1行外,每一行记录着一个特殊元素的行、列、值。】
               [2]  行2   列2    值2      【稀疏数组的第0列记录着行,第1列记录着列,第2列记录着值】
            */
        int sum = 0;
        for (int[] object : array1) {  // 遍历二维数组中的一维数组对象
            for (int value : object) {  // 遍历一维数组对象中的具体元素
                if (value != 0) {
                    sum++;  // 获取特殊元素个数
                }
            }
        }
        int[][] array2 = new int[sum + 1][3];  // 稀疏数组的行为特殊元数个数+1。因为第1行记录着原数组的总行、总列、特殊值总个数。
        array2[0][0] = 11;
        array2[0][1] = 11;
        array2[0][2] = sum;
        int row = 1;  // row从1开始,作为稀疏数组的行。
        for (int i = 0; i < array1.length; i++) {  // 遍历二维数组的行(一维数组对象)
            for (int j = 0; j < array1[i].length; j++) {  // 遍历二维数组的列(一维数组对象中的元素)
                if (array1[i][j] != 0) {
                    array2[row][0] = i;  // i为特殊值的行的下标
                    array2[row][1] = j;  // j为特殊值的列的下标
                    array2[row][2] = array1[i][j];
                    row++;
                }
            }
        }
        System.out.println("稀疏数组:");
        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i][0] + "\t"
                    + array2[i][1] + "\t"
                    + array2[i][2] + "\t");
        }
        System.out.println("=============================================");
        // 3.通过稀疏数组还原原数组
        int[][] array3 = new int[array2[0][0]][array2[0][1]];
        for (int i = 1; i < array2.length; i++) {  // 从稀疏数组的第1行开始遍历,将所记录的特殊元素的信息进行还原。
            array3[array2[i][0]][array2[i][1]] = array2[i][2];  // 根据记录的行、列、值精准赋值。array[记录的行][记录的列]=记录的值。
        }
        for (int[] object : array3) {
            for (int value : object) {
                System.out.print(value + "\t");
            }
            System.out.println();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值