首页 > 技术文章 > Java基础回顾《数组》

lpnxy 2021-08-27 23:55 原文

Java基础回顾《数组》

1、数组的概述

数组的定义

  1. 数据是相同类型数据的有序集合
  2. 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成
  3. 其中每一个数据称作一个数组元素,每一个数组元素可以通过下标来访问

数组的四个基本特点

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

2、数组声明创建

dataType[] nums = new dataType[arraySize] 创建数组的方法

定义数组:

  1. int[] nums ;
  2. int nums[]; //c和c++的声明方式
package com.f_Array;

public class ArrayDemo01 {
    public static void main(String[] args) {
        // 变量的类型 变量的名字 = 变量的值;
        // 数组类型=基础类型后[]

        // 定义数组的方式一
        int[] nums;//声明一个数组但没有分配空间
        //数组的创建
        int[] num = new int[10];// 声明一个数组并给他分配了空间下标是0-9
        //方式二
        int nums2[];// c 和 c++的数组申明方式 一般都用方式一为首选

        // 给num 赋值
        for (int i=0;i<num.length;i++){// 下标是从0开始的
            num[i]=i;// 用循环给数组赋值
            System.out.println(num[i]); //输出数组里面的值0-9
        }

    }
}

三种初始化以及内存分析

Java内存分析

  1. 堆,堆是用来存放New对象和数组的 可以被所有的线程共享,不会存放别的对象引用
  2. 栈,存放基本变量类型(包含这个基本类型的具体数值),引用对象的变量(会存放这个引用在堆里面的地址)
  3. 方法区,可以被所有线程共享 包含了所有的class 和static变量

如图:

image

初始化数组的方式

package com.f_Array;

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

        // 初始化数组的方式
        // 1、静态初始化: 创建+赋值
        int[] a = {1,2,3,4,5,6};
        System.out.println(a[1]);

        // 2、动态初始化: 包含默认初始化
        // 数组的初始值都是0 String类型的初始值为null 需要我们去进行赋值
        int[] b = new int[10];
        b[0] = 10;
        System.out.println(b[0]);
        System.out.println(b[1]);


        // String 类型
        String[] c = new String[10];
        c[0] ="helloworld";
        System.out.println(c[0]);
        System.out.println(c[1]);
    }
}

3、数组使用

数组的常用方式

  1. For循环数组获取元素或者下标
  2. For-Each循环增强型for循环(只能获取到元素获取不到下标)
  3. 数组作方法入参
  4. 数组作返回值(一般是对数组进行修改比如数组的反转)

案例如下

package com.f_Array;

public class ArrayDemo04 {
    public static void main(String[] args) {
        // 数组进阶使用 数组作方法入参 数组做返回值
        // 1、增强型for循环可以直接输出数组中的元素但是获取不到下标 array.for  For-Each循环(增强型for循环)
        System.out.println("=====================数组增强型for循环输出元素========================");
        int[] array = {1,2,3,4,5,6};
        for (int arr : array) {
            System.out.print(arr+"\t");
        }

        // 数组做方法入参
        System.out.println();// 换行
        System.out.println("=================数组做方法入参结果如下================");
        printArray(array); //方法调用


        // 数组反转(数组做返回值的使用)
        System.out.println();// 换行
        System.out.println("=================数组反转结果如下================");
        int[] reverse = reverse(array); // 定义一个int类型的reverse数组 数组的结果是调用reverse(array)方法后返回的结果
        printArray(reverse);//调用printArray方法循环打印输出reverse数组中的元素
    }

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

    // 3、反转数组
    public  static int[] reverse(int[] array){
        int[] result = new int[array.length];//定义了一个空数组
        // 反转的操作 result[] = array[i];
        for (int i =0,j=result.length-1;i<array.length;i++,j--){
                result[j] = array[i];
        }


        return result;
    }

}

4、多维数组

什么是多维数组?多维数据就是数组的数组可能听起来比较玄乎?先来看看二维数组

二维数组

可以理解成一个特殊的一维数组,其每一个元素都是一个一维数组

int arr[][] = new int[2][5]//创建一个二维数组arr
    //二维数组arr可以看成一个两行五列的数组

image

5、Arrays类

Arrays类是一个数组的工具类我们已通过Jdk帮助文档去查看里面的方法,或者通过idea里面的strucTure进行查看,方法有很多不明白的时候可以去看jdk帮助文档里面的解释非常清楚

package com.f_Array;

import java.util.Arrays;

public class ArrayDemo06 {
    public static void main(String[] args) {
    // Arrays类的使用
        int[] array = {1,2,3,564,68,65,8,1,53,4,891,98,489,165,65,18915};

        System.out.println(array);// [I@4554617c hashCode编码
         // 打印数组
        System.out.println(Arrays.toString(array));
        System.out.println("==========调用自己写的printArray方法==========");
        printArray(array);
        System.out.println();
        System.out.println("===========sort对数组进行排序===========");
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));


        // fil填充
//        Arrays.fill(array,0);
//        System.out.println(Arrays.toString(array));//[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

        // 可以对方法进行重载
        Arrays.fill(array,2,4,0);// 下标在2-4之间的数包括2 被0填充
        System.out.println(Arrays.toString(array));
    }
    //工具类里面的方法都是已经写好的方法 我们自己也可以去写
    public static void printArray(int[] array){
        for (int i = 0; i<array.length;i++){
            if (i==0){
                System.out.print("[");
            }
            if (i==array.length-1){
            System.out.print(array[i]+"]");
            }else {
                System.out.print(array[i]+", ");
            }
        }
    }
}

6、冒泡排序

冒泡排序是最出名的排序算法之一,经常出现在面试,笔试手写

思路:两两进行比较,谁小或者谁大就往前移或则后移

Java中总共有八大排序 可以去作为了解

  1. 冒泡排序的代码还是相对比较简单的,两层循环,外循环冒泡轮数,里层依次比较
  2. 看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为0(n2)
package com.f_Array;

import java.util.Arrays;

public class ArrayDemo07 {
    /**
     * 冒泡排序
     * 1、比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置
     * 2、每一次比较都会产生出一个最大或者最小的数字
     * 3、下一轮则可以少排序一次
     * 4、依次循环知道结束
     */
    public static void main(String[] args) {
    int[] array = {1,5,3,6,489,324,5,9,6,666,8};
        int[] sort = sort(array);
        System.out.print(Arrays.toString(sort));

    }

    public static int[] sort(int[] array){
        // 定义一个临时变量
        int temp = 0;

        // 外层循环判断我们这个要走多少次
        for (int i = 0;i<array.length-1;i++){//i<array.length-1防止溢出 因为下标是从0开始的
                // 内层循环,比较两个数,如果第一个数比第二个数大,则交换位置
                for (int j =0;j<array.length-1-i;j++){ // 每进行一次比较下一次比较都可以少比较一个数
                    if (array[j+1]<array[j]){
                        //位置交换 通过第三方变量实现交换  把三个变量看成一个三角形 要想实现值的交换就要通过temp 变量来进行
                        // 可以理解成如何把两杯水通过第三个杯子来进行相互交换
                       temp = array[j];
                       array[j] = array[j+1];
                       array[j+1] = temp;

                    }
                }
        }
        return array;
    }
}

想想如何优化=>

通过建立标识符减少一次比较,也可以对程序进行优化

package com.f_Array;

import java.util.Arrays;

public class ArrayDemo07 {
    /**
     * 冒泡排序
     * 1、比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置
     * 2、每一次比较都会产生出一个最大或者最小的数字
     * 3、下一轮则可以少排序一次
     * 4、依次循环直到结束
     */
    public static void main(String[] args) {
    int[] array = {1,5,3,6,489,324,5,9,6,666,8};
        int[] sort = sort(array);
        System.out.print(Arrays.toString(sort));

    }

    public static int[] sort(int[] array){
        // 定义一个临时变量
        int temp = 0;

        // 外层循环判断我们这个要走多少次
        for (int i = 0;i<array.length-1;i++){// i<array.length-1防止溢出 因为下标是从0开始的 
                // 内层循环,比较两个数,如果第一个数比第二个数大,则交换位置
                boolean flag = false;// 通过flag标识减少没有意义的比较也就是已经是比较好的元素
                for (int j =0;j<array.length-1-i;j++){ // 每进行一次比较 下一次比较都可以少比较一个数
                    if (array[j+1]<array[j]){
                        //位置交换 通过第三方变量实现交换  把三个变量看成一个三角形 要想实现值的交换就要通过temp 变量来进行
                        // 也可以理解成如何把两杯水通过第三个杯子来进行相互交换
                       temp = array[j];
                       array[j] = array[j+1];
                       array[j+1] = temp;
                       flag = true;
                    }
                }
                if (flag==false){
                    break;
                }
        }
        return array;
    }
}

7、稀疏数组(数据结构)

个人理解

其实普通二维数组转稀疏数组就是把 普通数组看成一个几行几列的棋盘 ,一个普通数组创建之后如果不赋值那么他的默认值就是0

在这个棋盘里面分别下两颗子(也就是数组里面的值) 那么问题来了 如果是一个11行11列的数组,里面只存了两个值的话岂不是大材小用? 来看如下原始数组(棋盘)

0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0
0 0 2 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0

这个时候稀疏数组的作用就来了 稀疏数组就是来压缩空间的,虽然他也是一个普通的二维数组但是他却固定了只有3列用来存储分别用来存储这两个棋子的横坐标,纵坐标,和有效值,这3列也有固定的下标 0(行), 1(列), 2(有效值)至于多少行,这就要看这个棋盘上有多少个有效值再加1,为什么加1 我们总不能把稀疏数组的第一行也算进去吧,他的第一行就是用来存储转换稀疏数组之前这个原始数组有

【多少行,多少列,几个有效值】=>11行 11列 2个有效值

11 11 2
0 0 0
0 0 0

转换后的值 => 原始数组有11行 11列 2个 有效值 第1行第2列的有效值是1 第2行第3列的有效值是2

11 11 2
1 2 1
2 3 2
一瞬间就把一个11行11列的数组压缩成了 一个3行3列的数组

案例

package com.f_Array;

public class ArrayDemo08 {
    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[] ints : array1) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
        // 转化为稀疏数组来保存
        // 获取有效值的个数
        int sum = 0;
        for (int i = 0; i < 11; i++) {
            for (int j = 0; j < 11; j++) {
                if (array1[i][j] != 0) {
                    sum++;
                }
            }
        }
        System.out.println("有效值得个数是:" + sum);

        //2.创建一个稀疏数组的数组
        int[][] array2 = new int[sum + 1][3]; // 稀疏数组的数组结构

        // 稀疏数组的头部
        array2[0][0] = 11;  // 行
        array2[0][1] = 11;  // 列
        array2[0][2] = sum; // 有效值的个数

        // 打印看一下稀疏数组的结构  方便理解
        System.out.println("打印查看稀疏数组结构");
        for (int[] ints : array2) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
        /** 创建的稀疏数组的结构是这样的
         * 行   列    有效值
         * 11  11      2
         * 0   0      0
         * 0   0      0
         */

        // 遍历二维数组将非零的值。存放到稀疏数组中
        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[] ints : array2) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
      // 结果 由此可以看出稀疏数组存储的其实就是有效数字的坐标 n行 n列 有效值是多少
        /**
         * 11  11 2
         * 1   2  1
         * 2   3  2
         */
        // 3.如何把稀疏数组转为普通数组?
        System.out.println("==========================");
        System.out.println("稀疏数组还原");
        // 1.读取稀疏数组的元素
        int[][] array3 = new int[array2[0][0]][array2[0][1]]; // 就相当于int[11][11]

        // 2.给其中的元素还原值
        for (int i =1;i<array2.length;i++){
            array3[array2[i][0]][array2[i][1]] = array2[i][2]; // 行 列 值
        }
        // 3.打印输出查看是否还原
        System.out.println("输出还原数组");
        for (int[] ints : array3) {
            for (int anInt : ints) {
                System.out.print(anInt+"\t");
            }
            System.out.println();
        }
    }
}

结果

image

推荐阅读