尚硅谷Java零基础全套视频教程(宋红康2023版,java入门自学必备)数组2

二维数组的声明与初始化,推荐使用的二维数组声明的语法格式如下:

元素的数据类型[][] 二维数组的名称;

二维数组有一个特殊写法,int[] x, y[]; 其中x为一维数组,y为二维数组。其实,从数组底层的运行机制来看,其实没有多维数组,

二维数组也有两种初始化形式,分别是静态初始化和动态初始化。静态初始化如下

int[][] arr = new int[][]{{3, 8, 2}, {2, 7}, {9, 0, 1, 6}};

上述代码表示定义一个arr的二维数组,二维数组中有三个一维数组,其中每一个一维数组中的元素也进行了初始化,二维数组可看成是由多个一维数组组成,其中arr[0]={3, 8, 2}, arr[1]={2, 7}, arr[2]={9, 0, 1, 6}, 第三个一维数组的长度表示方式为arr[2].length;

动态初始化,如果二维数组的每一个数组,甚至是每一行的数据,需要后期单独确定,那么只能使用动态初始化方式。动态初始化方式有两种格式:

格式1:规则二维表:每一行的列数是相同的

  元素的数据类型[][] 二维数组名 = new 元素的数据类型[m][n];

  二维数组名[行下标][列下标] = 值;

格式2:不规则:每一行的列数不一样

  先确定行数

  元素的数据类型[][] 二维数组名 = new 元素的数据类型[总行数][];

  二维数组名[行下标] = new 元素的数据类型[该行的总列数];

  二维数组名[行下标][列下标] = 值;

对上述二维数组的声明与初始化进行总结,静态初始化与一维数组的静态初始化类似,只是多了几个[]与{},动态初始化分为两种情况,列数确定且列数相同和列数不确定,列数确定且列数相同可以在二维数组初始化时直接写出,如果列数不确定,则需对每一行进行一维数组赋值以确定列数。

数组声明和初始化的总结

静态初始化中,由于已知具体元素就不用在new 后的[]中写明数组长度,这适用于一维数组和二维数组初始化。

动态初始化中,由于不知具体元素,所以要在new后的[]中写明数组长度,这适用于一维数组和列数已知且相同的二维数组,对于列数未知且不相同的数组,先在new后的第一个[]中标明行数,然后依次对每一行进行赋值,写明列数。

数组的长度和角标

二维数组名.length表示二维数组的长度/行数,二维数组的某一行:二维数组名[行下标],测试相当于获取其中的一组数据,本质上是一个一维数组。行下标的范围:[0,二维数组名.length-1],把二维数组看成一维数组的话,元素是行对象。某一行的列数为二维数组名[行下标].length,因为二维数组的每一行是一个一维数组。获取某一个元素通过二维数组名[行下标][列下标],先确定行/组,再确定列。

二维数组的内存解析,二维数组本质上元素类型是一维数组的一维数组。

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

在main方法中先给变量arr一个地址,地址中装的是二维数组中的第一行的地址,二维数组第一行的地址中装的是第一行第一列的元素地址。arr中所有行变成一个一维数组,一维数组的内容是对应行第一列元素的地址,如下图所示

int[][] arr = new int[5][];

for(int i=0; i<arr.length; i++){

      arr[i] = new int[i+1];

}

for(int i=0; i<arr.length; i++){

      for(int j=0; j<arr[i].length; j++){

             arr[i][j] = i+1;

      }

}

上述代码,首先在main()方法中创建一个变量arr,arr的值为首行元素的地址,由于不知道首行第一列元素的地址,所以arr中地址的内容为空,其余行也不知道首列元素的地址,所装的内容都为空。等到第二个for循环开始,所有行首列元素地址都已知,所有行地址的内容都为对应行首列元素的地址。其中每一行的内存都和一维数组的内存相同,所有行的内存也和一维数组的内存相同

数组的常见算法

数组的特征值计算(平均值、最大值、最小值、总和等)

数组复制,其中将两个数组的其中一个数组,数组一 = 数组二,数组一和数组二所指向的地址相同,若想真正的实现复制,则需重新创建一个数组,并依次赋值,这就完成了数组的复制。

数组元素的反转

利用中间变量将对称位置元素互换实现数组反转

数组的扩容与缩容

利用新建的数组,将原数组的元素赋值给新数组,然后再新数组中添加元素,最终将新数组赋值给原数组,实现数组扩容

想要删除某个位置的元素,利用它后面的元素,用后面的元素覆盖掉它的值,然后将空位赋值0

数组元素的查找

顺序查找,对数组元素的顺序没有要求,复杂度为O(N),但算法写起来简单

二分法查找,数组必须是有序的(降序和升序都可以),复杂度为O(log2N),算法写起来难

数组元素排序

排序的定义为:假设含有 n 个记录的序列为{R1,R2,...,Rn},其相应的关键字序列为 {K1,K2,...,Kn}。将这些记录重新排序为{Ri1,Ri2,...,Rin},使得相应的关键字 值满足条 Ki1<=Ki2<=...<=Kin,这样的一种操作称为排序。个人理解,关键字为具体可比较的数字。

将数组进行排序的目的是为了快速查找。

衡量排序算法的优劣:

             时间复杂度:分析关键字的比较次数和记录的移动次数(重要)

             常见的算法时间复杂度由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)< Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)<O(nn)

             空间复杂度:分析排序算法中需要多少辅助内存。一个算法的空间复杂度S(n)定义为该算法所耗费的存储空间,它也是问题规模n的函数。

             通常会使用空间来换取时间,提升运算速度。

             稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。

排序算法可以分为内部排序和外部排序,内部排序是整个排序过程不需要借助外部存储器,所有排序操作都在内存中完成;外部排序参与的数据非常多,数据量非常大,无法把整个排序过程放在内存中完成,整个排序过程需要借助外部存储器完成,可以认为外部排序是由多次内部排序组成。

十大内部排序算法中,最常用的是冒泡排序,写起来相对简单,实际开发中常用的是快速排序。冒泡排序的平均时间复杂度为O(n2),快速排序的平均时间复杂度为O(nlog2n)。

冒泡排序,冒泡排序的排序思想

      比较相邻的两个元素,如果第一个比第二个元素大,就交换他们两个

      对每一对相邻的元素作同样的工作,从开始第一对到结尾的最后一对,做完之后,得到的元素会是最大的数。

      针对所有的元素重复以上的步骤,除了最后一个,最后一个已经不需要比较

      持续每次对越来越少的元素重复上面的步骤,知道没有任何一对数字需要比较为止。

快速排序,时间复杂度为O(nlogn),排序思想如下

      从数列中挑出一个元素,称为“基准”

      重新排列数组,所有元素比基准值小的摆放在基准前面,所有元素比基准大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个成为分区操作。

      递归地把小于基准值元素的子数列和大于基准值的子数列排序

      递归的最底部情形,是数列的大小为零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代中,它至少会把一个元素摆到它最后的位置去。

我们需要关注的排序是冒泡排序和快速排序,需要掌握快速排序的思想

Array工具类的使用

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

比较两个数组的元素是否相等,使用boolean Arrays.equals(int[] a, int[] b)方法

输出数组元素信息,String toString(int[] a)输出数组元素信息

将指定值填充到数组之中,void fill(int[] a, int val):将指定值填充到数组之中,数组中全部替换成该值

使用快速排序算法实现排序,void sort(int[] a)使用快速排序算法进行排序

使用二分查找查找元素,int binarySearch(int[] a, int key),使用前提,数组必须是有序的

数组中异常小结

数组角标越界异常,下标出现[0, 数组名.length-1]的范围时,就会报数组下标越界异常:ArrayIndexOutOfBoundsException

空指针异常,NullPointerException,int[][] arr = new int[3][];,当你输出arr[0][0]时,会出现空指针异常,因为arr[0][0]没有分配具体的地址

对应解决办法,出现异常程序会停止运行,针对异常信息修改代码,避免异常再次出现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值