The Definition And Use OF Arrays - 数组的定义与使用(万字长篇)

文章目录

  • 什么是数组
    • 举个例子,我现在要创建一个整形数组
    • 注意事项: 在 Java 中, 数组中包含的变量必须是 相同类型
  • 创建数组
    • 1.静态初始化
      • 基本语法
      • 程序实例
    • 既然创造出数组,就必然有它存在的价值,那么数组的好处是什么?
    • 而且对数组有一定了解的人,都知道**数组的每个元素都有一个下标(从0开始)**,方便去寻找寻找元素.
      • 图1
    • 注意事项: 静态初始化的时候, 数组元素个数和初始化数据的格式是一致的(依据初始化元素的数量,来决定数组的大小)
    • 2.动态初始化
      • 基本语法
      • 代码实例
    • 第三种创建数组的方法
      • 基本语法:
      • 代码实例
    • 总结
  • 数组的使用
    • 代码实例1(获取数组的长度)
      • 图2
    • 代码实例2 (读取数组中某个元素)
      • 图3
    • 代码实例3(数组越界问题)
      • 图4
    • 续代码3
      • 图 5
    • 代码实例4(改变数组某元素的值)
      • 图6
    • 注意事项
  • 遍历数组
    • 代码实例1(for循环 - 遍历打印数组元素)
      • 图7
    • 代码实例2(增加for循环 - foreach - 图 8)
      • foreach 基本语法:
      • 图 8
      • 图9
    • 那么 for 和 foreach 两者有什么区别?
    • 代码实例3(借助Java的操作数组的工具类 Arrays 图10)
      • 图10
      • 图11
      • 图12
  • 数组作为方法的参数
    • 首先我们需要搞懂几样东西
      • 看代码
      • 图13(这图没截好,下半部分少了东西,不过无伤大雅)
    • 代码实例
      • 图14
      • 图15
    • 现在我们来尝试用方法来遍历打印数组
      • 代码如下
      • 图16
      • 图17
    • 实践题
      • 题目一
      • 题目2
      • 图 18
      • 图19
    • 图解(图20)
    • 还有一个问题值得讨论:一个引用 是否 能同时 指向 多个对象?
    • 结论
    • 另外注意
  • 这时候,我们来讲讲前面文章留下来的问题(使用方法,来交换两个变量的值)
    • 图21
  • 数组作为方法的返回值
    • 代码示例: 写一个方法, 将数组中的每个元素都 * 2
      • 先来写没有返回值的(将原来的数组元素都扩大2倍)
      • 图 22
      • 图23
    • 现在我们来写有返回值的(不在原来的数组上扩大2倍,保护原来的数组不被破坏)
      • 代码入下
      • 图24
      • 图25
  • 数组练习
    • 模拟实现 toString 函数
      • 代码如下
      • 图26
    • 找数组中的最大元素
      • 图27
    • 查找数组中指定元素(顺序查找),返回它的下标
    • 查找数组中指定元素(二分查找),返回其下标
      • 图28
      • 图29
    • 其实在Java中有一个工具,就是二分查找,意味这我们没必要像上面一样去写一个二分查找的方法
      • 写法: Arrays.binarySearch(数组名,想查找的元素)
      • 代码如下
      • 图30
      • 图31
      • 图32
    • 二分查找对于有序数列的效率是非常高的,你想想取一个中间下标的值
      • 图33
    • 检查数组的有序性(升序:从左往右,从小到大)
      • 图34
      • 图35
    • 数组排序(冒泡排序)
      • 升序
      • 图36
      • 图37
    • 经过上面的讲解,至少你对冒泡有一定的了解,很遗憾,我想告诉你,我们辛辛苦苦做出的冒泡排序,在Java是有函数可以做到的(但并不意味我们刚才的努力都是白费,万一面试官,让你模拟实现一个冒泡排序呢?)对吧? 废话不多说,我们来看看这哥函数是什么?
      • Arrays.sort
      • 图38
      • 图39
    • 我们在顺便拓展一下 Arrays 的其它功能
      • Arrays.fill
      • 图 40
      • 图41
      • 图42
    • 根据图 43,发现 Arrays。fill 的参数,还可以写两个
      • 图43
      • 图44
    • 数组逆序
      • 图45
    • 数组数字排列
      • 图46
  • 数组拷贝
    • 拷贝方法1 循环拷贝
      • 代码如下
      • 图47
      • 图48
    • 方法2
      • 图 49
      • 代码如下
      • 图50
      • 图51
      • 图52
    • 方法3
      • 图53
    • 但是我们先来看第四种方法,为第三种方法做铺垫
      • Arrays.copyOfRange()
      • 图54
      • 代码如下
      • 图 55
    • 好,现在我们来看看 第三方法
      • 图56
    • 拓展
      • 图 57
    • 方法 5 数组克隆
      • 基本语法:
      • 图58
  • 在 一维数组的最后我们在讲一个概念, 深拷贝 和 前拷贝
    • 图 59
  • 二维数组
    • 二维数组的创建
      • 基本语法1
      • 基本语法2
      • 基本语法3
        • 跟一维数组几乎一样,只要初始化了数据,你的[][]里就不能有数字的存在
      • 代码如下
    • 二维数组的打印
      • 图60
      • 图 61
      • 图 62
      • 接着我们来对上面的程序(二维数组的打印)进行改良
      • 图63
    • 前面使用for循环来打印数组,这回我们foreach
      • 图64
    • 还有一种输出二维数组的方法
      • 图65
    • 接下来,我会让你们见识到一种特别的二维数组
      • 代码案例
      • 图66
    • 再来举个例子
      • 图67
      • 图68
      • 图69
      • 图70
    • 哪有人可能会问,虽然写法没问题,但是程序运行会报错,那么省略列的意义在哪?
      • 代码如下
      • 图71
      • 图72
  • 本文结束。

什么是数组

数组本质上就是让我们能 "批量" 创建相同类型的变量也可以说是存储一组相同数据类型的数据的集合

举个例子,我现在要创建一个整形数组

 int[] array
int[] 就是相当于是一个类型(整形数组类型),
而 array 就相当于 该类型的变量
总得来说 就是我创建一个变量,它的类型是整形数组类型再来看看这个 int a =10; a是变量,类型是int,且只能存储一个值。
而 int[] array,array是变量,类型是int[],它能存储一组相同类型的数据(能存储类型相同的数据,个数不限,取决你想放多少个类型相同的数据)
例: int[] array ={1,2,3,4,5,6}

注意事项: 在 Java 中, 数组中包含的变量必须是 相同类型


创建数组

1.静态初始化

基本语法

    数据类型[] 数组名称 = { 初始化数据 };

程序实例

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array ={1,2,3,4,5,6};//数据类型[]+数组名称 = { 初始化数据 }; 如果后面已将数组初始化元素值了,其中[]里不能加任何数字,这是Java创建数组时,静态初始化的一个特点.}
}

既然创造出数组,就必然有它存在的价值,那么数组的好处是什么?

如果我们没有数据的支持,我们想要定义 6 个整形会变得巨繁琐,反正我学了数组,像例子这种呆头呆脑的写就没用过了。

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int a = 1;int b = 2;int c = 3;int d = 4;int e = 5;int f = 6;}
}

而且对数组有一定了解的人,都知道数组的每个元素都有一个下标(从0开始),方便去寻找寻找元素.

而且是所有元素都存储在一块连续的空间上,所以从内存上看,所有元素都是紧邻(图1)

图1

在这里插入图片描述

注意事项: 静态初始化的时候, 数组元素个数和初始化数据的格式是一致的(依据初始化元素的数量,来决定数组的大小)


2.动态初始化

基本语法

数据类型[] 数组名称 = new 数据类型 [] { 初始化数据 };

代码实例

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = new int[]{1,2,3,4,5,6};//其表达意思与作用与第一种方法相同,就是创建一个数组,并初始化数据// 两个[]中,都不能有数字的存在// new 是java中的一个关键字,其作用是实例化一个对象// 意味着 在Java 数组其实是一个对象。对象具体是什么,后面再降// (注意,并不是前面有new,数组才是一个对象,而是数组本来是就是一个对象)//先这么认为,数组就是一款网页游戏,游戏没打开之前,它只是一个图标,而new的作用就是加载这游戏成为实体,就是运行起来。}
}

第三种创建数组的方法

基本语法:

    类型[] 数组名 = new 类型[元素个数];就是第二种方法中,删除了初始化数据,前者的[]中是不能有数字的存在,后者的[]可以有具体的数字来表示数组元素的个数

代码实例

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = new int[6];// 该写法表达的意思是 现在有一个数组,长度为6,注意数组的元素,并没有对其初始化,在Java中,默认6个元素都是0// 等价于 int[] array={0,0,0,0,0,0},}
}

总结

 一套讲解下来,你会发现在Java中 是这么来表达一个数组:int[] array其实数组也可以写成int arr[] = {1, 2, 3};和 C 语言一样. 但是我们还是更推荐写成 int[] arr 的形式. int和 [] 是一个整体.,因此,其实在Java中数组的写法更为准确。但是不能像C语言一样这样写 int array[10] = {0};
我们前面也看到了,在创建一个数组时,[]里是不能有具体数字的存在,除了第三种方法,其它的,一律不行。

数组的使用

代码实例1(获取数组的长度)

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};// 注意在Java是没有sizeof这种东西的,那么有人可能会问,在数组元素个数未知的情况下,我们该如何获得数组元素个数?//  方法 : 数组名.length   这样写Java就会自动获取数组的长度(元素个数)。System.out.println(array.length);}// 图2
}

图2

在这里插入图片描述


代码实例2 (读取数组中某个元素)

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array={1,2,3,4,5};// 下标从0开始,4的下标就是 3// 访问方法: 数组名[下标]System.out.println(array[3]);}// 图 3
}

图3

在这里插入图片描述


代码实例3(数组越界问题)

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array={1,2,3,4,5};// 下标从0开始递增,也就是正数下标,不存在所谓的负数下标System.out.println(array[-1]);// 我们将访问元素的下标写成负数,让我们来看看效果如何。}// 图 4
}

图4

在这里插入图片描述


续代码3

 还有一种情况:元素只有 5 个,下标最高为4,你却要访问第6个元素,也就是下标为 5 的元素
public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array={1,2,3,4,5};System.out.println(array[5]);// 现在我们将访问元素的下标写成5,让我们来看看效果如何。}// 图 5
}

图 5

在这里插入图片描述


代码实例4(改变数组某元素的值)

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array={1,2,3,4,5};// 改变 元素3 的值,也就是改变数组中下标为2的元素值// 方法 数组名[下标] = 新值;array[2]=8;System.out.println(array[2]);// 让我们来看看效果如何。}// 图 6
}

图6

在这里插入图片描述


注意事项

    1. 使用 arr.length 能够获取到数组的长度.    . 这个操作为成员访问操作符. 后面在面向对象中会经常用到.2. 使用 [ ] 按下标取数组元素. 需要注意, 下标从 0 开始计数3. 使用 [ ] 操作既能读取数据, 也能修改数据.4. 下标访问操作不能超出有效范围 [0, length - 1] , 如果超出有效范围, 会出现下标越界异常

遍历数组

代码实例1(for循环 - 遍历打印数组元素)

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array={1,2,3,4,5};for (int i = 0; i < array.length; i++) {System.out.print(array[i]+" ");// println 是因为它自带换行,输出结果是竖着的,不好看。// 所以我使用的是 print 打印不换行}//图 7}
}

图7

在这里插入图片描述


代码实例2(增加for循环 - foreach - 图 8)

foreach 基本语法:

 for(定义一个 与数组元素类型 相同的变量 : 数组名)什么意思呢?
foreach(增加for循环), 数组名部分,表示的意思 遍历访问数组的元素
将访问的元素赋给 冒号前面 定义的 与数组元素类型相同 的变量我们只需要 将该变量每次得到的元素值,打印就能做到不依靠元素下标,遍历打印数组所有元素
public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};for (int x:array) {System.out.print(x+" ");}}//图9
}

图 8

在这里插入图片描述

图9

在这里插入图片描述


那么 for 和 foreach 两者有什么区别?

最大的区别在于,for是可以拿到元素下标,而foreach拿不到元素下标for循环用到的地方很多,但是foreach呢?
当我们只需要元素的值时,就是使用foreach,当我们还需要元素的下标时,就用for。
for-each 是 for 循环的另外一种使用方式. 能够更方便的完成对数组的遍历. 可以避免循环条件和更新语句写错

代码实例3(借助Java的操作数组的工具类 Arrays 图10)

toString 将当前的数组元素,转换成字符串形式,并将其返回(也可以说 将参数的数组,以字符串形式进行输出)
import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};String str = Arrays.toString(array);// 创建一个字符串变量来接收它的返回值System.out.println(str);// 图 11// 因为 Arrays.toString 是有返回值的,所以可以直接输出System.out.println(Arrays.toString(array));//图12}
}

图10

在这里插入图片描述


图11

在这里插入图片描述


图12

在这里插入图片描述


数组作为方法的参数

首先我们需要搞懂几样东西

看代码

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array ={1,2,3,4,5};int a = 10;}
}

array 和 a 都是局部变量,在栈上开辟空间
那么问题来了,a的空间里存的是 10
而数组后面的一大坨数据,放在哪里?
和 10 一样放在栈上?
然而并不是,还记得前面说到 数组是一个对象吗?
对象是存放在 堆上的.
在这里我们就需要介绍一些东西,图13


图13(这图没截好,下半部分少了东西,不过无伤大雅)

在这里插入图片描述


引用很像指针,最大的区别就是不能对 引用 解引用可以对指针解引用,因为在Java没有传址的概念的其他功能类似,但时两个东西,不是同一个东西,不能混淆在一起。


有个问题就诞生了,指针有空指针,那引用有空引用(引用里面存的地址是空的)吗?
答案是有的,只不过跟C语言不同,C是大写NULL,Java是小写null
但是请注意,举这个例子只是为了让你理解引用是一个什么东西,顺便区别两者。
C的东西只是辅助你理解Java,尽量学Java的时候,抛开C,两者(引用和指针)有很多不同地方。


代码实例

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};int[] array1 = null;//当一个引用被赋予null,就代表这该引用不指向任何对象// 既然该引用不指向任何对象,那么我这样写代码会怎么样?System.out.println(array1.length);// 求一个空引用所指向的对象的长度,但是空引用不会指向任何一个对象的// 何来的长度?那么代码运行的效果如何?14,由图可知该写法是错误的,另外引用被指为null,堆上是不会分配内存给它的// 意思是你都不创建任何对象,你还想拿我空间,疯了?System.out.println(array1[0]);// 这个写法毫无疑问也是错的,没对象,你怎么访问对象里的东西?来看看图 15}
}

图14

在这里插入图片描述

图15

在这里插入图片描述


现在我们来尝试用方法来遍历打印数组

代码如下

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};print(array);}public static void print(int[] array){for (int x:array) {System.out.print(x+" ");}System.out.println();// 换行for (int i = 0; i < array.length; i++) {System.out.print(array[i]+" ");}}// 效果见图16
}//让我们通过 图17 来说明

图16

在这里插入图片描述


图17

在这里插入图片描述
举个例子,你玩游戏DNF,有仓库对吧,你会设密码对吧?要不然被盗号,就算找回来,里面的东西也不见了。
只要别人知道你的密码,他不就可以拿里面的东西了吗?
按引用传递,就相当于你找朋友刷东西,把密码告诉他,这样他才能打开你的仓库,在里面拿或者取 装备和材料,不然他怎么刷的动?


实践题

下面两题先思考答案,再去看结果附图,这样你们才能对引用的理解进一步加深
下面两题的输出结果是什么?

题目一

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};func1(array);System.out.println(Arrays.toString(array));// 图 18}public static void func1(int[] array){array = new int[]{11,2,13,4,51};}}

题目2

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};func2(array);System.out.println(Arrays.toString(array));}public static void func2(int[] array){array[0] = 99;}
}//图19









图 18

在这里插入图片描述


图19

在这里插入图片描述


##题目路2的两个array等价于下面的程序 array 和 array2

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};int[] array2 = array;这代表  array2 这个引用 指向 引用array指向 的对象array 和 array2 指向的是同一个对象}}

图解(图20)

在这里插入图片描述


还有一个问题值得讨论:一个引用 是否 能同时 指向 多个对象?

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array1 = new int[]{1,2,3,4,5};array1 = new int[10];array1 = new int[2];array1 = new int[4];}
}

答案是不能,如果前面认真看了,就该知道此时的array1,存储的地址,已经被改变array是一个局部变量,意味着存的值是可以被改变的,现在存的是 new int[4] 的这个对象的地址, 而不是说,存几个对象的地址。


结论

 一个引用只能指向一个对象(一个引用只能保存一个对象的地址)

另外注意

 写了这么多,有没有发现我们写的引用,都是在栈上那么 引用 就一定在栈上吗?答案是不一定的,因为一个变量在不在栈上,是你变量的性质决定的如果你的引用是一个局部变量,那就一定在栈上实例成员变量那就不一定了。(先告诉你们有这个概念,等后面讲到成员变量时,再说)局部变量的引用保存在栈上, new 出的对象保存在堆上.堆的空间非常大, 栈的空间比较小.因为 堆 是整个 JVM 共享一个,而 栈 每个线程具有一份 (一个 Java 程序中可能存在多个栈)

这时候,我们来讲讲前面文章留下来的问题(使用方法,来交换两个变量的值)

因为Java中是取不到栈上变量的地址的,也就意味不能传址,所以无法按照C一样去实现但是今天我们学了数组,我们用数组的方式来解决问题
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {//int a = 10;//int b = 20;// 我们将其放在一个数组里,进行交换int[] array = {10,20};swap(array);System.out.println(Arrays.toString(array));}public static void swap(int[] array){int tmp = array[0];array[0] = array[1];array[1] = tmp;}
}// 图21,这只是一种取巧的方式来进行交换,等到我讲到类和对象的那个时候,会再讲几种方法

图21

在这里插入图片描述


数组作为方法的返回值

代码示例: 写一个方法, 将数组中的每个元素都 * 2

先来写没有返回值的(将原来的数组元素都扩大2倍)

import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array={1,2,3,4,5};func(array);System.out.println(Arrays.toString(array));}public static void func(int[] array){for (int i = 0; i < array.length; i++) {array[i]=2*array[i];}}//图22
}// 图解(图23)

图 22

在这里插入图片描述


图23

在这里插入图片描述


现在我们来写有返回值的(不在原来的数组上扩大2倍,保护原来的数组不被破坏)

代码入下

import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array={1,2,3,4,5};int[] ret = func(array);//建立数组类型(对象)变量来接收System.out.println(Arrays.toString(ret));System.out.println(Arrays.toString(array));}public static int[] func(int[] array){int[] ret = new int[array.length];for (int i = 0; i < array.length; i++) {ret[i]=2*array[i];}return ret;//这里返回是 新建对象(数组),在堆上的地址}//图24
}// 图解(图25)

图24

在这里插入图片描述


图25

在这里插入图片描述
这样的话就不会破坏原有数组了.
另外由于数组是引用类型, 返回的时候只是将这个数组的首地址返回给函数调用者, 没有拷贝数组内容, 从而比较高效.
有的人可能会说,方法调用完的时候,不是会销毁栈上的空间,我们这样将地址带回来,不会存在一些问题吗?
请注意 new 的对象,都是存在堆上的,而不是栈上。这里的返回的是将堆上对象的地址(注意返回类型int[]),而不是局部变量ret,所以不会出现问题


数组练习

模拟实现 toString 函数

 toString 将当前的数组元素,转换成字符串形式,并将其返回(也可以说 将参数的数组,以字符串形式进行输出) 图12

代码如下

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array={1,2,3,4,5};String str = myToString(array);System.out.println(str);}public static String myToString(int[] array){if(array == null){return "null";// 判断是否形参接收的地址,是否为空指针}String str = "[";for (int i = 0; i < array.length; i++) {str+=array[i];// 用了一开始拼接输出方式,字符串开头后面用+拼接,使其成为一个字符串if(i< array.length-1){// array.length-1,因为最后一个元素不用加 ,号str+=",";}}str+="]";return  str;}
}// 图26

图26

在这里插入图片描述


找数组中的最大元素

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {12,8,1,2,10};System.out.println(maxNum(array));}public static int maxNum(int[] array){if(array==null){return -1;// 假设 -1 意味着array存储的是空指针}if(0 == array.length){return -2;// 假设 -2 意味着 array 没有元素(int[] array = {})// 故 数组长度为0(元素个数为0).}int max = array[0];for (int i = 1; i < array.length; i++) {if(max<array[i]){max = array[i];}}return max;}// 图 27
}

图27

在这里插入图片描述


查找数组中指定元素(顺序查找),返回它的下标

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,23,213,67,123};System.out.println(find(array,23));}public static int find(int[] array,int y){for (int i = 0; i < array.length; i++) {if (array[i] == y){return i;}}return -1;// 表示没找到,因为数组的下标不可能存在负数}
}

在这里插入图片描述


查找数组中指定元素(二分查找),返回其下标

    针对有序数组, 可以使用更高效的二分查找
public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};System.out.println(find(array,4));}public static int find(int[] array,int y){int right = array.length-1;// 右下标int left = 0;// 左下标int mid = 0;while(right>=left){mid=(right+left)/2;if(array[mid]>y){right--;}else if(array[mid]<y){left++;}else{return mid;}}return -1;//表示没找到}
}// 图28图释( 图29

图28

在这里插入图片描述


图29

在这里插入图片描述


其实在Java中有一个工具,就是二分查找,意味这我们没必要像上面一样去写一个二分查找的方法

写法: Arrays.binarySearch(数组名,想查找的元素)

代码如下

import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};System.out.println(Arrays.binarySearch(array,2));// 图30// 如果找一个不存在的数呢?System.out.println(Arrays.binarySearch(array,6));// 图 31// 有人会好奇,为什么是-6?// 左键点击 binarySearch,ctrl + 左键点击// 再点击 binarySearch,ctrl + 左键点击你会看到 图 32// -(low+1),意思是最后low的位置下标+1,取负// 因为我们要找的数,比有序数组里所有元素都要大,所以最后low的位置应该最后一个元素的位置// 也就是下标为 5 的位置,对其加一取负,所以输出的值是-6// 另外注意,下标是没有负数的,别以为这-6 是一个元素的下标,不是的啊。// 只是告诉你找不到。// 下标不可能为负,你给我个负数,不是找不到是什么}
}

图30

在这里插入图片描述


图31

在这里插入图片描述


图32

在这里插入图片描述


二分查找对于有序数列的效率是非常高的,你想想取一个中间下标的值

  不管你要找的数,是大于或者小于这个值,都意味着有一边的数据直接pass。

图33

在这里插入图片描述


检查数组的有序性(升序:从左往右,从小到大)

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,10,5,6};System.out.println(isSorted(array));}public static  boolean isSorted(int[] array){for (int i = 0; i < array.length-1; i++) {
//    注意 array.length-1,为什么减一呢?因为你想想看,假设有6个元素(array.length == 6)
//   但是下标最大为 5 == array.length-1,因为有小于号,所以这个减一,可以被省略,那为什么还要减一?
//   注意我们的if条件(array[i]>array[i+1]),当循环元素到下标为5的元素(最后一个元素),就会有问题了
// array[i+1] == array[6] == 第七个元素,第七个元素有没有?没有。那我们访问的话会产生数组越界访问错误
// 图35if(array[i]>array[i+1]){// 左边的元素比右边的元素大,那么就不满足升序,称为乱序return false;// 乱序}}return true;// 有序}
}// 图34

图34

在这里插入图片描述

图35

在这里插入图片描述


数组排序(冒泡排序)

升序

import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {9,5,2,7};// 我们假设一个整形数组bubbleSort(array);// 调用我们的自定义的冒泡的方法,把我们的数组名(引用)扔过去,按引用传递System.out.println(Arrays.toString(array));// 偷个油,不用循环打印,将其转换成字符串输出}public static void bubbleSort(int[] array){// 创建一个 数组变量,来接收传参// 理一下思绪,首先假设我定义一个 i 来表示元素下标,通过引用(数组名) 和 [] 来访问下标所对应的函数。//既然要排升序,肯定要比较大小,不可能自己跟自己比吧?要跟它后面的元素比,比它大,相互交换位置,反则什么都不做(升序)。// 但是不可能只比一次,我这里有四个元素,至少要比3次,才能完成把最大的数放在最后。// 有的人可能会说,不是有4个元素吗?不应该是4次,记住我们2个一比,每次都是前面比后面,// 到了倒数第二个元素,它是最后的元素相比较,比较完了,那么最后一个元素已经最大的了,还有比较的意义吗?没有!//而且这是,一趟,还要比较3趟。我们第一趟比较只是把最大的数,放到了最后,其它三个数,还不知是否是升序36// 现在我们正式开始for (int i = 0; i < array.length; i++) {// 有4个元素,需要比 3 趟// 根据 图36 最后的结论,表示有可能,在未来完成某一趟比较之后,后面的数值已经有序,那我们没有比较的必要// 所以 我们在这里定义一个 flag = 1,再在 交换程序中 写一个flag=0;// 什么意思呢? 就是你只要交换了两元素的位置,说明这一趟,数组肯定不是有序的,你都交换了,还有序?// 如果 这一趟下来flag还是等于1,我们结束整个排序,为什么?因为根据图36来看,冒泡排序的比较模式 是交换式比较,// 1 和 2 一比,比完; 2 和 3一比,也就是如果flag等于1,说明后面没有发生交换// 后面的每一位都比自身前一位都要大(比前面的位,早在之前就给你换了)//  说明升序排列完成int flag =1;// 假设这一趟是有序的// 每一趟的比较过程for (int j = 0; j < array.length-1-i; j++) {// 减一是为了防止越界,这个应该都懂// 至于减 i,想想看,我们每一趟比较,把最大的数往后排,小的数往前挪,作为下一次标胶的起点// 再加上这一趟比下来,可以说一个数跟其他都比较了,只有全比较了,我们才能知道最大数究竟是谁?// 得出了最大数,放在最后,那还有比较的必要,再去比,就是疯了。(都打过一架了,还输了,你还找别人去单挑,不是疯了,就是zz)// 所以每比完一趟,我们比较次数就减一,// 第一次,i==0,是因为倒数2个大值,还需要比较,你再减一个1,还比什么。搞黑手?还没比,就把最后的一位数,放在最后一位// 万一倒数第二位,比最后的数,要大呢?,这不是搞黑幕,是搞什么?嗯?if(array[j]>array[j+1]){// 升序,前者比后者小,只要前者比后者大,就意味着需要交换位置int tmp = array[j];array[j] = array[j+1];array[j+1]=tmp;// 假设//  2 1// tmp = 2 == array[0] ;  array[0] = array[1] == 1,此时array[0]已经被改变// array [1] = tmp ==2;// 即 数组元素顺序 为 1,2flag = 0;// 都交换了,那么肯定是不是有序的}}if(1== flag){break;//如果flag等于1,说明后面的每一位都比自身前一位都要大,那就说明没有比较的意义,同时意味着排序完成,跳出循环。}}来看看看结果 图 37}
}

图36

在这里插入图片描述


图37

在这里插入图片描述


经过上面的讲解,至少你对冒泡有一定的了解,很遗憾,我想告诉你,我们辛辛苦苦做出的冒泡排序,在Java是有函数可以做到的(但并不意味我们刚才的努力都是白费,万一面试官,让你模拟实现一个冒泡排序呢?)对吧? 废话不多说,我们来看看这哥函数是什么?

Arrays.sort

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {9,5,2,7};Arrays.sort(array);// 是借助Java工具Arrays.sort来完成的,图 39System.out.println(Arrays.toString(array));// 图38}
}

图38

在这里插入图片描述


图39

在这里插入图片描述


我们在顺便拓展一下 Arrays 的其它功能

Arrays.fill

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = new int[10];// 此时数组默认10个元素都是0,图40Arrays.fill(array,99);// fill 是 填的意思,图 42System.out.println(Arrays.toString(array));// 效果见 图 41}
}

图 40

在这里插入图片描述


图41

在这里插入图片描述


图42

在这里插入图片描述


根据图 43,发现 Arrays。fill 的参数,还可以写两个

图43

在这里插入图片描述

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = new int[10];// 此时数组默认10个元素都是0,图40Arrays.fill(array,0,5,99);// 意思将下标为0的元素到下标为4的元素全部置为0// 至于为什么不是下标为5,是因为 该范围是 左闭右开 [0,5) ==   0=<下标 && 下标<5System.out.println(Arrays.toString(array));// 效果见 图 44}
}

图44

在这里插入图片描述


数组逆序

 假设数组元素顺序为 1,2,3,4,5(并不一定是有序,只是为了举例方便)
结果为       5,4,3,2,1
import java.util.Arrays;public  class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};echange(array);System.out.println(Arrays.toString(array));// 图 45}public static void echange(int[] array){int left =0;// 左下标int right = array.length-1;// 右下标while(left<right){// 就是两边的数据对着换// 当left 和 right 所指向的下标相遇是,也就同一个元素// 循环终止int tmp = array[left];array[left]=array[right];array[right]= tmp;right--;left++;}}
}

图45

在这里插入图片描述


数组数字排列

给定一个整型数组, 将所有的偶数放在前半部分, 将所有的奇数放在数组后半部分 例如{1, 2, 3, 4}调整后得到{4, 2, 3, 1}
import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4};transform(array);System.out.println(Arrays.toString(array));// 图 46}public static void transform(int[] array){int left = 0;int right = array.length-1;while(left<right){while(left<right && array[left]%2 == 0){// 找奇数(%2 !=0),找到了,跳出循环left++;// left 是不能一直加加的,如果没有 left// 甚至可能会越界(全偶数),因为(小)循环体执行完了,才会去判断(大)循环条件,}while(left<right && array[right]%2 != 0 ){// 找偶数(%2 == 0),找到了,跳出循环right--;// 这个与left同理}int tmp = array[left];array[left] = array[right];array[right] = tmp;}}
}

图46

在这里插入图片描述


数组拷贝

拷贝方法1 循环拷贝

 假设你要拷贝的数组 是 int[] array = {1,2,3,4,5}那么我就需要 创一个相同类型,元素个数相同的 数组变量array2来接收(int[] array2 [array.length])
通过 对应的下标进行复制拷贝

代码如下

import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array={1,2,3,4,5};int[] array2 = copyOf(array);// 是方法中 引用ret存储值的一份拷贝,能够访问 ret 指向的堆上的对象System.out.println(Arrays.toString(array));System.out.println(Arrays.toString(array2));// 图 47}public static int[] copyOf(int[] array){int[] ret = new int[array.length];//创一个相同类型,元素个数相同的 数组变量array2来接收 array 的元素for (int i = 0; i < array.length; i++) {ret[i] = array[i];//通过 对应的下标进行复制拷贝}return  ret;// 将对象的地址转过去}
}// 图 48

图47

在这里插入图片描述


图48

在这里插入图片描述


方法2

 利用Java提供的函数: Arrays.copyOf图49

图 49

在这里插入图片描述

代码如下

import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};int[] array2 = Arrays.copyOf(array,array.length);System.out.println(Arrays.toString(array2));// 图 50// 既然能规定 拷贝数量,我输入拷贝数量超过,源数组array的元素个数呢?int[] array3 = Arrays.copyOf(array,array.length*2);System.out.println(Arrays.toString(array3));// 图 51,由图可知类似扩容}// 但是注意一点,本质是copy明白嘛? 这扩容出来的数组,跟元素组,不是同一个数组左键点击copyOf +Ctrl+左键),来看看得到的  图52 ,由图52,还可以得知 如果我们想"扩容",输入的倍数必须整数,因为它的长度类型规定为整形
}

图50

在这里插入图片描述


图51

在这里插入图片描述


图52

在这里插入图片描述


方法3

不知道你们注意到没? 图52中的一个程序语句图 53
图中所圈部分,就是我们拷贝数组的第三种方法

图53

在这里插入图片描述


但是我们先来看第四种方法,为第三种方法做铺垫

Arrays.copyOfRange()

图54

在这里插入图片描述

代码如下

import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};int[] ret = Arrays.copyOfRange(array,0,4);System.out.println(Arrays.toString(ret));//图 55}
}

图 55

在这里插入图片描述


好,现在我们来看看 第三方法

在这里插入图片描述

import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};int[] array2 = new int[array.length];System.arraycopy(array,0,array2,0,array.length);// 跟用for循环进行拷贝时一个道理,根据对应的下标进行赋值拷贝System.out.println(Arrays.toString(array2));// 图 56}
}

图56

在这里插入图片描述


拓展

图 57

在这里插入图片描述

注意图中所圈部分,怎么进我就不再教了,忘了就往上翻。
我来提示你,System.arraycopy是不是没有实现过程,只是一个类似函数声明一样,放在那里?
那它是怎么实现数组拷贝的呢?
这就跟我们所圈起来的native(本地的)有关,
所有被 native 所修饰的方法,方法的实现过程,都已经被 C/C++ 实现了
我们是看不到运行过程的,这样写的最大好处就是 速度快,效率高


方法 5 数组克隆

基本语法:

 数组名.clone();
import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[] array = {1,2,3,4,5};int[] array2 = array.clone();// 类似 副本,不是游戏副本啊!// 可以理解为是一份资料的备份System.out.println(Arrays.toString(array2));}// 图58
}

图58

在这里插入图片描述


在 一维数组的最后我们在讲一个概念, 深拷贝 和 前拷贝

图 59

在这里插入图片描述


&ensp;

二维数组

二维数组的创建

基本语法1

数据类型[][] 数组名 = { 初始化数据 }

基本语法2

 数据类型[][] 数组名 = new 数据类型[][]{ 初始化数据 }

基本语法3

  数据类型[][] 数组名 = new 数据类型[行数][列数]

跟一维数组几乎一样,只要初始化了数据,你的[][]里就不能有数字的存在

代码如下

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {// 创建一个 2行3列的二维数组int[][] array = {{1,2,3},{4,5,6}};int[][] array2 = new int[][]{{1,2,3},{4,5,6}};int[][] array3 = new int[2][3];}
}

二维数组的打印

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {// 创建一个 2行3列的二维数组int[][] array = {{1,2,3},{4,5,6}};int[][] array2 = new int[][]{{1,2,3},{4,5,6}};int[][] array3 = new int[2][3];print(array);}public static void print(int[][] array){// 按照我们以前对C的理解,二维数组的存储模式应该为 图60for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++) {//打印一行数据System.out.print(array[i][j] + " ");}System.out.println();// 换行}}
}// 效果图 61

图60

在这里插入图片描述


图 61

在这里插入图片描述

由图的结果来看没问题
但是我总不能,每个二维数组都自己去算它有几个元素吧。
问题就在于怎么去获得 行 和 列
这里就引用C语言的一个概念,二维数组是一个特殊的一维数组
经过前面讲解,大家都知道数组是存储在堆上的,再加上面这句话的概念
让我们看看图62


图 62

在这里插入图片描述


接着我们来对上面的程序(二维数组的打印)进行改良

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {// 创建一个 2行3列的二维数组int[][] array = {{1,2,3},{4,5,6}};int[][] array2 = new int[][]{{1,2,3},{4,5,6}};int[][] array3 = new int[2][3];print(array);// 这里我们在用实例证明一下// array.length 是否能的得到 行数 2System.out.println(array.length);// array[下标].length 是否能得到 列数3System.out.println(array[0].length);System.out.println(array[1].length);}public static void print(int[][] array){// 按照我们以前对C的理解,二维数组的存储模式应该为图60for (int i = 0; i < array.length; i++) {for (int j = 0; j < array[i].length; j++) {//打印一行数据System.out.print(array[i][j] + " ");}System.out.println();// 换行}}
}// 图63 

图63

在这里插入图片描述


前面使用for循环来打印数组,这回我们foreach

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[][] array = {{1,2,3},{4,5,6}};print(array);}public static void print(int[][] array){for (int[] ret:array) {// array元素的数据类型是一个一维数组,我就需要一个相同的类型的变量来接收for (int x:ret) {// ret是一个一维数组的数组名,接下来就跟前面使用foreach是一样,将 引用ret 所指向的对象(数组)的元素,// 读取并赋值给 与其元素类型相同的变量, 我们再将其输出。就可以了System.out.print(x + " " );}System.out.println();//换行}}
}// 图 64

图64

在这里插入图片描述


还有一种输出二维数组的方法

 在前面,我们使用了 Arrays.toString,将数组转换的字符串输出二维数组也有对应的 方法: Arrays.deepToString(数组名)
import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[][] array = {{1,2,3},{4,5,6}};System.out.println(Arrays.deepToString(array));}
}//图 65

图65

在这里插入图片描述


接下来,我会让你们见识到一种特别的二维数组

代码案例

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[][] array = {{1,2},{1,2,3}};for (int[] ret:array) {for (int x:ret) {System.out.print(x+" ");}System.out.println();// 换行}}
}//图 66,见证奇迹,参考图62

图66

在这里插入图片描述
在这里插入图片描述


再来举个例子

public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[][] array = new int[2][];// 在C语言中,二维数组,是不能省略列的,行可以省略// 而Java与之相反,行不能省略,列可以(图67、68)for (int i = 0; i < array.length; i++) {for (int j = 0; j < array[i].length; j++) {System.out.print(array[i][j] + " ");}System.out.println();// 换行}}//图 69,图 70
}

图67

在这里插入图片描述


图68

在这里插入图片描述


图69

在这里插入图片描述


图70

在这里插入图片描述


哪有人可能会问,虽然写法没问题,但是程序运行会报错,那么省略列的意义在哪?

 意义在于我们可以改,去赋予
这种二维数组,我们将其称为 不规则的二维数组,

代码如下

import java.util.Arrays;public class TheDefinitionAndUseOfArrays {public static void main(String[] args) {int[][] array = new int[2][];array[0]=new int[3];// 意味着第一个数组长度为3array[1]=new int[2];// 意味着第二个数组长度为2System.out.println(Arrays.deepToString(array));}
}// 图71,72

图71

在这里插入图片描述

图72

在这里插入图片描述

本文结束。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部