JAVA基础知识(三)——数组

数组

    • 数组
        • 一、数组的概述
          • [1.1 数组的定义](#1.1 数组的定义)
          • [1.2 数组的常见概念](#1.2 数组的常见概念)
          • [1.3 数组的特点](#1.3 数组的特点)
          • [1.4 数组的分类](#1.4 数组的分类)
        • 二、一维数组的使用
          • [2.1 一维数组的声明和初始化](#2.1 一维数组的声明和初始化)
          • [2.2 数组的基本使用](#2.2 数组的基本使用)
          • [2.3 数组元素的默认初始化值](#2.3 数组元素的默认初始化值)
          • [2.4 数组的内存解析](#2.4 数组的内存解析)
        • 三、多维数组的使用
          • [3.1 二维数组的理解](#3.1 二维数组的理解)
          • [3.2 二维数组的声明](#3.2 二维数组的声明)
          • [3.3 二维数组的引用](#3.3 二维数组的引用)
          • [3.4 二维数组的默认初始化值](#3.4 二维数组的默认初始化值)
          • [3.5 二维数组的内存分析](#3.5 二维数组的内存分析)
          • [3.6 二维数组的练习](#3.6 二维数组的练习)
        • 四、数组中常见的算法
          • [4.1 数组中涉及的常见算法](#4.1 数组中涉及的常见算法)
          • [4.2 二分法查找算法](#4.2 二分法查找算法)
          • [4.3 排序算法](#4.3 排序算法)
          • [4.4 冒泡排序](#4.4 冒泡排序)
          • [4.5 快速排序](#4.5 快速排序)
          • [4.6 各种内部排序方法性能比较](#4.6 各种内部排序方法性能比较)
          • [4.7 排序算法的选择](#4.7 排序算法的选择)
          • [4.8 Arrays工具类的使用](#4.8 Arrays工具类的使用)

数组

一、数组的概述

1.1 数组的定义

数组(Array) ,是多个相同类型数据一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。

1.2 数组的常见概念
  • 数组名
  • 下标(或索引)
  • 元素
  • 数组的长度
1.3 数组的特点
  • 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型
  • 创建数据对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址
  • 数组的长度一旦确定,就不能修改
  • 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。
1.4 数组的分类
  • 按照维度:一维数组、二维数组、三维数组、...
  • 按照元素的数据类型分:基本数据类型元素的数组、引用数据类型元素的数组(即对象数组)

二、一维数组的使用

2.1 一维数组的声明和初始化
  • 静态初始化:数组的初始化和数组元素的赋值操作同时进行
  • 动态初始化:数组的初始化和数组元素的赋值操作分开进行
java 复制代码
           //1. 一维数组的声明和初始化
        int num; //声明
        num = 10;
        int id = 1001;// 声明+ 初始化

        int[] ids;//声明
        //1.1 静态初始化:数组的初始化和数组元素的赋值操作同时进行
        ids = new int[]{1001, 1002, 1003, 1004};

        int id2[] = new int[]{1001, 1002, 1003, 1004};
        
        //1.2 动态初始化:数组的初始化和数组元素的赋值操作分开进行
        String[] names = new String[5];
  • 错误的写法
java 复制代码
        int[] arr1 = new int[];
        
        int[5] arr2 = new int[5];
        
        int[] arr3 = new int[3]{1, 2,4};
2.2 数组的基本使用
  • 定义并用运算符new为之分配空间后,才可以引用数组中的每个元素;
  • 数组元素的引用方式:数组名[数组元素下标 ]
    • 数组元素下标可以是整型常量或整型表达式。如a[3] , b[i] , c[6*i];
    • 数组元素下标从0开始;长度为n的数组合法下标取值范围: 0 --->n-1;如int a[]=new int[3]; 可引用的数组元素为a[0]、a[1]、a[2]
  • 每个数组都有一个属性length指明它的长度,例如:a.length 指明数组a的长度(元素个数)
    • 数组一旦初始化,其长度是不可变的
java 复制代码
 //总结:数组一旦初始化完成,其长度就确定了
 
//(2)如何调用数组指定位置的元素:通过索引的方式调用
//数组的索引是从0开始的,到数组的长度-1结束
names[0] = "张三";
names[1] = "李四";
names[2] = "王五";
names[3] = "赵六";
names[4] = "孙七";
 
//3、如何获取数组的长度
//属性 length
System.out.println(ids.length);
System.out.println(names.length);
 
//4、如何遍历数组
for (int i = 0; i < ids.length; i++){
    System.out.println(ids[i]);
}
 
for (int i = 0; i < names.length; i++){
    System.out.println(names[i]);
}
2.3 数组元素的默认初始化值

数组是引用类型,它的元素相当于类的成员变量,因此数组一经分配空间,其中的每个元素也被按照成员变量同样的方式被隐式初始化。

数组元素类型 元素默认初始值
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
char 0或写:'\u0000' (表现为空)
boolean false
引用数据类型 null
java 复制代码
        System.out.println("----------byte数组初始化值-----------");
        byte[] byteArray = new byte[1];
        for (int i = 0; i < byteArray.length; i++) {
            System.out.println(byteArray[i]);
        }
        System.out.println("----------short数组初始化值-----------");
        short[] shortArray = new short[1];
        for (int i = 0; i < shortArray.length; i++) {
            System.out.println(shortArray[i]);
        }
        System.out.println("----------int数组初始化值-----------");
        int[] intArray = new int[1];
        for (int i = 0; i < intArray.length; i++) {
            System.out.println(intArray[i]);
        }
        System.out.println("----------long数组初始化值-----------");
        long[] longArray = new long[1];
        for (int i = 0; i < longArray.length; i++) {
            System.out.println(longArray[i]);
        }
        System.out.println("----------float数组初始化值-----------");
        float[] floatArray = new float[1];
        for (int i = 0; i < floatArray.length; i++) {
            System.out.println(floatArray[i]);
        }
        System.out.println("----------double数组初始化值-----------");
        double[] doubletArray = new double[1];
        for (int i = 0; i < doubletArray.length; i++) {
            System.out.println(doubletArray[i]);
        }
        System.out.println("----------char数组初始化值-----------");
        char[] charArray = new char[1];
        for (int i = 0; i < charArray.length; i++) {
            System.out.println(charArray[i]);
        }
        System.out.println("----------boolean数组初始化值-----------");
        boolean[] booleanArray = new boolean[1];
        for (int i = 0; i < booleanArray.length; i++) {
            System.out.println(booleanArray[i]);
        }
        System.out.println("----------引用类型数组初始化值-----------");
        String[] stringArray = new String[1];
        for (int i = 0; i < stringArray.length; i++) {
            System.out.println(stringArray[i]);
        }
java 复制代码
----------byte数组初始化值-----------
0
----------short数组初始化值-----------
0
----------int数组初始化值-----------
0
----------long数组初始化值-----------
0
----------float数组初始化值-----------
0.0
----------double数组初始化值-----------
0.0
----------char数组初始化值-----------
 
----------boolean数组初始化值-----------
false
----------引用类型数组初始化值-----------
null
2.4 数组的内存解析
  • jvm示意图
  • 数组内存解析示例:
java 复制代码
int[] arr = new int[]{1,2,3};
String[] arr1 = new String[4];
arr1[1] = "刘德华";
arr1[2] = "张学友";
arr1 = new String[3];

三、多维数组的使用

3.1 二维数组的理解
  • Java 语言里提供了支持多维数组的语法
  • 如果说可以把一维数组当成几何中的线性图形,那么二维数组就相当于是一个表格,像右图Excel中的表格一样。
  • 对于二维数组的理解,我们可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。其实,从数组底层的运行机制来看,其实没有多维数组。
  • 二维数组:数组中的数组。
3.2 二维数组的声明
java 复制代码
         //1.二维数组的声明和初始化
        int[] arr =  new int[]{1, 2, 3};//一维数组
        //静态初始化
        int[][] arr1 =  new int[][]{{1,2,3}, {4,5,6}, {7,8}};
        //动态初始化
        String[][] arr2 = new String[3][2];

        String arr3[][] = new String[3][2];
        String[] arr4[] = new String[3][2];
  • 非法
java 复制代码
int[][]arr = new int[][3]; //非法
3.3 二维数组的引用
java 复制代码
//静态初始化
int[][] arr1 = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8}};
//动态初始化1
int[][] arr2 = new int[3][2];
//动态初始化2
int[][] arr3 = new int[3][];
 
//这样也是正确的 但是不推荐
//        int arr4[][];
//        int[] arr4[];
 
//2、如何调用数组指定位置的元素
System.out.println(arr1[0][1]);//2
System.out.println(arr2[1][1]);//0
 
arr3[1] = new int[2];
System.out.println(arr3[1][1]);//0
 
//3、获取数组的长度
System.out.println(arr1.length);//3
System.out.println(arr1[0].length);//3
System.out.println(arr1[1].length);//3
 
//4、如何遍历二维数组
for(int i = 0; i < arr1.length; i++){
    for (int j = 0; j < arr1[i].length; j++){
        System.out.print(arr1[i][j] + " ");
    }
    System.out.println();
}
3.4 二维数组的默认初始化值
java 复制代码
        //int类型
        int[][] arr = new int[3][];
        System.out.println(arr[0]);// null
// System.out.println(arr[0][0]); //NullPointerException
        System.out.println(arr); //[[I@1b6d3586

        int[][] arr1 = new int[3][4];
        System.out.println(arr1[0]);// [I@1b6d3586 地址值
        System.out.println(arr1[0][0]); //0
        System.out.println(arr1); //[[I@74a14482

//float类型
        float[][] arr3 = new float[3][4];
        System.out.println(arr3[0]);// [F@1540e19d 地址值
        System.out.println(arr3[0][0]); //0.0

//String类型
        String[][] arr4 = new String[3][4];
        System.out.println(arr4[0]);// [Ljava.lang.String;@677327b6 地址值
        System.out.println(arr4[0][0]); //null
3.5 二维数组的内存分析
java 复制代码
int[][] arr1 = int[4][];
arr1[1] = new int[]{1,2,3};
arr1[2] = new int[4];
arr1[2][1] = 30;

int[4][] 中int[0]的值为null, 是因为此时的int[]引用类型没有赋值 所以是null

3.6 二维数组的练习
  • x 表示int[] y 表示int[][] y[0] 表示int[]
  • 一维数组:int[] x 或者int x[];
  • 二维数组:int[][] y 或者int[] y[]或者int y[][]
java 复制代码
注意:x 表示int[] y 表示int[][] y[0] 表示int[]
声明:int[] x,y[];在给x,y变量赋值以后,以下选项允许通过编译的是:
a) x[0] = y;//错误 类型不一致 x是一维数组 y是二维数组
b) y[0] = x; //编译通过
c) y[0][0] = x;//y[0][0]表示的是值, x表示的是地址值
d) x[0][0] = y;//错误
e) y[0][0] = x[0];//编译通过
f) x = y; //错误 x表示int[],y表示int[][]

四、数组中常见的算法

4.1 数组中涉及的常见算法
  • 数组元素的赋值(杨辉三角、回形数等)
  • 求数值型数组中的最大值、最小值、平均数、总和等。
  • 数组的复制、反转、查找(线性查找、二分法查找)
  • 数组元素的排序算法
4.2 二分法查找算法
java 复制代码
    public static void main(String[] args) {
       int[] array = {1,4,5,23,45,67};
       int targetNum = -67;
       binarySearch(array, targetNum);
    }

    public static void binarySearch(int[] source, int targetNum) {
           int head = 0;
           int end =  source.length -1;
           while(head <= end) {
               int middle = (head+end)/2;
               if (source[middle] > targetNum) {
                   end = middle - 1;
               } else if (source[middle] < targetNum) {
                   head = middle + 1;
               } else {
                   System.out.println("数据找到了" + source[middle] + "当前位置为" + middle);
                   break;
               }
       }
       if (head > end) {
           System.out.println("数据未找到" + targetNum);
       }
    }
4.3 排序算法
  • 排序:假设含有n个记录的序列为{R1,R2,...,Rn},其相应的关键字序列为{K1,K2,...,Kn}。将这些记录重新排序为{Ri1,Ri2,...,Rin},使得相应的关键
    字值满足条Ki1<=Ki2<=...<=Kin,这样的一种操作称为排序。
  • 通常来说,排序的目的是快速查找。
  • 衡量排序算法的优劣:
    • 时间复杂度:分析关键字的比较次数和记录的移动次数
    • 空间复杂度:分析排序算法中需要多少辅助内存
    • 稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。
  • 排序算法分类
    • 内部排序:整个排序过程不需要借助于外部存储器(如磁盘等),所有排序操作都在内存中完成。
    • 外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器(如磁盘)。外部排序最常见的是多路归并排序。可以认为外部排序是由多次内部排序组成。
  • 十大内部排序算法
    • 选择排序:直接选择排序、堆排序
    • 交换排序: 冒泡排序、快速排序
    • 插入排序:直接插入排序、折半插入排序、Shell排序
    • 归并排序
    • 桶式排序
    • 基数排序
  • 算法的5大特征
4.4 冒泡排序
  • 介绍

    冒泡排序的原理非常简单,它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

  • 排序思想

    • 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
    • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
    • 针对所有的元素重复以上的步骤,除了最后一个。
    • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止。
java 复制代码
//冒泡排序 
 public static void bubbleSort(int[] source) {
        for (int i = 0; i < source.length; i++) {
            for (int i1 = i + 1; i1 < source.length; i1++) {
                if (source[i] < source[i1]) {
                    int temp = source[i];
                    source[i] = source[i1];
                    source[i1] = temp;
                    continue;
                }
            }
        }
        for (int i : source) {
            System.out.print(i + " ");
        }
    }

    //改进
    public static void bubbleSortUpgrade(int[] source) {
        for (int i = 0; i < source.length-1; i++) {//最后一个数不用在继续比较啦
            for (int i1 = i + 1; i1 < source.length-1-i; i1++) {//不用在和之前的数据去进行比较啦
                if (source[i] < source[i1]) {
                    int temp = source[i];
                    source[i] = source[i1];
                    source[i1] = temp;
                    continue;
                }
            }
        }
        for (int i : source) {
            System.out.print(i + " ");
        }
    }
//数组反转 方式一
    public static void arrayInversion(int[] source) {
        int[] newSource = new int[source.length];
        for (int i = source.length - 1,j=0; i >= 0; i--,j++) {
            newSource[j] = source[i];
        }
        for (int i : newSource) {
            System.out.print(i + " ");
        }
    }
    
    //数组反转 方式二
    public static void arrayInversionTwo(int[] source) {
        for (int i = 0; i < source.length/2; i++) {
            int temp = source[i];
            source[i] = source[source.length-i-1];
            source[source.length-i-1] = temp;
        }
        for (int i : source) {
            System.out.print(i + " ");
        }
    }
//获取最大值
    public static void getArrayMax(int[] source) {
        int max = source[0];
        for (int i = 0; i < source.length; i++) {
            if (max < source[i]) {
                max = source[i];
            }
        }
        System.out.println("max = " + max);
    }
//获取最小值
    public static void getArrayMin(int[] source) {
        int min = source[0];
        for (int i = 0; i < source.length; i++) {
            if (min > source[i]) {
                min = source[i];
            }
        }
        System.out.println("min = " + min);
    }
4.5 快速排序
  • 介绍
    快速排序通常明显比同为O(nlogn)的其他算法更快,因此常被采用,而且快排采用了分治法的思想,所以在很多笔试面试中能经常看到快排的影子。可见掌握快排的重要性。
    快速排序(Quick Sort)由图灵奖获得者Tony Hoare发明,被列为20世纪十大算法之一,是迄今为止所有内排序算法中速度最快的一种。冒泡排序的升级版,交换排序的一种。快速排序的时间复杂度为O(nlog(n))。
  • 排序思想:
    从数列中挑出一个元素,称为"基准"(pivot),
    重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
    递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
    递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
4.6 各种内部排序方法性能比较
  • 从平均时间而言:快速排序最佳。但在最坏情况下时间性能不如堆排序和归并排序。
  • 从算法简单性看:由于直接选择排序、直接插入排序和冒泡排序的算法比较简单,将其认为是简单算法。对于Shell排序、堆排序、快速排序和归并排序算法,其算法比较复杂,认为是复杂排序。
  • 从稳定性看:直接插入排序、冒泡排序和归并排序时稳定的;而直接选择排序、快速排序、 Shell排序和堆排序是不稳定排序
  • 从待排序的记录数n的大小看,n较小时,宜采用简单排序;而n较大时宜采用改进排序。
4.7 排序算法的选择
  • 若n较小(如n≤50),可采用直接插入或直接选择排序。当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直
    接插入,应选直接选择排序为宜。
  • 若文件初始状态基本有序(指正序),则应选用直接插入、冒泡或随机的快速排序为宜;
  • 若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
4.8 Arrays工具类的使用

java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法。

方法 作用
boolean equals(boolean[] a, boolean[] a2) 判断两个数组是否相等
String toString(int[] a) 输出数组信息
void fill(int[] a, int val) 将指定值填充到数组中
void sort(int[] a) 对数组进行排序
int binarySearch(int[] a, int key) 对排序后的数组进行二分法检索指定的值
java 复制代码
int[] array = {99,76,64,43,33,32,32,21,0,-98};
       int[] array1 = {99,76,64,43,33,32,32,21,0,-98};

       int[] array3 = {99};
      //  System.out.println(Arrays.equals(array3, array2));
        System.out.println(Arrays.equals(array1, array));
        System.out.println(Arrays.toString(array));

        System.out.println("------------填充之前--------------");
        Arrays.fill(array, 156);
        Arrays.fill(array, 0, 3, 157);
        System.out.println(Arrays.toString(array));
        System.out.println("------------填充之后--------------");

        System.out.println("------------排序前--------------");
        Arrays.sort(array1);
        Arrays.sort(array1);
        System.out.println(Arrays.toString(array1));
        System.out.println("------------排序之后--------------");
       // int[] array2 = {99,76,64,43,33,32,21,0,-98};
        int[] array2 = {-98,0,21,32,33,43,64,76,99};
        System.out.println(Arrays.binarySearch(array2, 33));//有序的数组,且从小到大排列
        System.out.println(Arrays.binarySearch(array2, 64));
        //System.out.println(Arrays.binarySearch(array2, 3));
相关推荐
蒙娜丽宁8 分钟前
《Python OpenCV从菜鸟到高手》——零基础进阶,开启图像处理与计算机视觉的大门!
python·opencv·计算机视觉
光芒再现dev9 分钟前
已解决,部署GPTSoVITS报错‘AsyncRequest‘ object has no attribute ‘_json_response_data‘
运维·python·gpt·语言模型·自然语言处理
王俊山IT10 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
为将者,自当识天晓地。12 分钟前
c++多线程
java·开发语言
小政爱学习!14 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
daqinzl20 分钟前
java获取机器ip、mac
java·mac·ip
好喜欢吃红柚子23 分钟前
万字长文解读空间、通道注意力机制机制和超详细代码逐行分析(SE,CBAM,SGE,CA,ECA,TA)
人工智能·pytorch·python·计算机视觉·cnn
小馒头学python28 分钟前
机器学习是什么?AIGC又是什么?机器学习与AIGC未来科技的双引擎
人工智能·python·机器学习
k093329 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
激流丶36 分钟前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic