Java基础--数组练习2

简介: Java基础--数组练习2

请添加图片描述

@[toc]

一、数组知识回顾

之前咱们学了数组的基础知识,并做了小练习。

还不清楚数组基本知识的戳这里,非常详尽!!!

本次将继续带大家做数组练习,数组非常重要,希望大家能够熟练掌握。

接下来先梳理一下前面说过的知识点,看看你是否都知道呢,不清楚的可以看我之前的文章哦。

(1)概念

数组是用来存储一组相同数据类型的数据的容器。

将一组数据统一地管理起来。

(2)特点

1.数组是一个引用数据类型

2.数组内部可以存储的元素,可以是基本类型,也可以是引用类型

3.数组是在堆内存中一串连续的地址

4.数组在初始化时必须指定长度及内部存储元素类型(静态/动态都有)。

5.如果需要用变量来进行存储,变量空间在栈内存中,变量中存储的是数组引用(地址)

6.堆内存的数组空间长度一旦确定,不能再次发生改变

(3)创建数组

数组的定义(创建 声明):

    数组内部类型[]  数组名字; 

如:

int[] array;

(4)数组的初始化

数组的初始化(创建并赋值):

①静态初始化-->有长度(元素个数),有元素(元素能够看得见)

数组内部类型[]  数组名字=new  数组内部类型[]{元素};

如:

int[] array=new int[]{1,2,3,4,5};
//这个数组(array),有5个元素,具体元素也能看得见。

②动态初始化-->只有长度(元素个数),没有元素(不是真的没有,都是默认值)

数组内部类型[]  数组名字=new  数组内部类型[元素个数]; 
//元素个数只能是0以上的(包括0)。
//如果是0,就是创建了一个长度为0的数组,没有意义。
//如果长度小于0,会出现一个“编译时异常”,数组长度不合法(Negative Array Size Exception)的错误。

如:

int[] array=new int[5];
//这个数组(array),有5个元素,具体元素看不见,都是默认值,int类型的默认值为0

这个初始化的过程,就是在堆内存中实实在在地创建了一个数组。

就是在堆内存中开辟的一串连续的地址空间 ,并赋了值。

:warning: 注意:

栈内存中没有元素,就是真的没有。

栈内存中都是变量,变量创建出来,,不往里面存东西,就是真的没有元素。

==栈内存里的变量没有初始化,就是真的没有元素。==

堆内存的元素,创建出来都是有默认值的。

现在是数组,创建在堆内存里,以后的对象也在堆内存里。

堆内存里的对象空间,里面的每一个值,如果不给它们赋值,都是有默认值存在的。

==堆内存里都是有默认值的。==

(5)数组元素的访问

数组元素的访问(存/取),是通过元素在数组中的位置(index索引)来访问的。

数组的索引从0开始,一直到数组长度-1结束。

如果索引出现范围以外的值(比0小或比长度减一大),就会产生一个运行时异常

即:Array Index Out Of Bounds Exception(数组索引越界)。

要求:1.记住错误英文名 2.知道这个错误如何产生的 3.以后遇到了会更正错误。

(6)数组元素的遍历

数组的遍历(轮询):

正常的for循环 / 增强for循环

正常for循环: 有索引,可以赋值,可以取值。但写法相对比较麻烦。

增强for循环:写法相对比较简单。但是没有索引,找不到位置,只能取值(用变量来接收值)。存的值在变量里,并不在数组里。

(7)内存结构

数组本身是一个引用数据类型

注意基本数据类型和引用数据类型之间的区别

它们在内存结构上的区别,即:基本类型存的是值,引用类型存的是址。

注:针对这个知识点,我专门写了一篇博文,不清楚的戳这里

二、数组练习之互换元素

案例一

01 需求

:car:给定一个数组a{1,2,3,4,5,6},将这个数组中的元素头尾对应互换位置。

02 分析

:cake:下面来剖析一下这个问题。

(1)创建数组

根据题意,创建一个数组,取名为array

int[] array;

(2)初始化

明显,数组内元素比较少,用静态初始化

标准写法:

int[] array=new int[]{1,2,3,4,5,6};

简洁写法:

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

(3)循环解决

我们要将这个数组里边的元素头尾互换,是重复同一件事情。

既然是同一件事情,就可以用循环来解决。

先来找一下规律。

int[] array={1,2,3,4,5,6};
array[0]<--->array[5]
array[1]<--->array[4]
array[2]<--->array[3]

array[i]<--->array[5-i]

循环一共执行3次,从几开始都可以,之前说过,从1-3可以,从10-12也可以。

但是,如果执行3次,可以和索引号对上,就比较方便。

==索引号也是个变量,如果循环变量和索引号变量变化一致,就会省去一个变量。==

索引号从0开始,那我们可以让循环变量也从0开始。

到什么时候结束?一共要循环3次。

那么循环三要素就有了。

for(int i=0;i<3;i++){ //控制3次
    
}

接下来是循环体,通过上面的规律,很容易得出这两个元素互换:

array[i]<--->array[5-i]

既然要互换元素,就要找一个中间变量,类型要和数组内元素数据类型一致,为int类型。

则咱们创建一个中间变量int x,并互换头尾元素:

int x=array[i];
array[i]=array[5-i];
array[5-i]=x;

整体for循环就写好了:

for(int i=0;i<3;i++){ //控制3次
    int x=array[i];
    array[i]=array[5-i];
    array[5-i]=x;
}

(4)输出

接下来,咱们输出结果看一看。

这里用增强for循环输出一下,因为这个for循环比较简单。

不知道的戳这里,在数组元素遍历第三点说过,具体位置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c1ImyyMk-1658755025562)(D:\Typora图片\image-20220725190939040.png)]

写出来的代码如下:

for(int v:array){
    System.out.println(v); //用变量v来接收数组内的元素,冒号后边是要遍历的数组
}

03 代码及执行

(1)代码

加上头尾,整体代码如下:

public class Test{
    public static void main(String[] args){
        //1.创建数组并初始化
        int[] array={1,2,3,4,5,6};
        //2.循环控制
        for(int i=0;i<3;i++){ //控制3次
                int x=array[i];
            array[i]=array[5-i];
            array[5-i]=x;
        }
        //3.输出
         for(int v:array){  
             System.out.println(v); 
         }
    }
}

(2)执行结果

执行结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CiI1UkOA-1658755025562)(D:\Typora图片\image-20220725191557041.png)]

可以看见,数组元素头尾互换了。

04 延拓

(1)问题

上面的题比较简单,但这里我想强调一点。

这里的数组是给我们的,元素啥的都是很清楚的。

如果给了我们一个不确定的数组,数组内部的元素我们不知道(这个数组是别人经过一系列操作生成的,不知道有什么元素)。

此时,需要我们将这个数组内部元素头尾互换。

那该咋办呢?

(2)分析

此时我们手里面是有这个数组的名字的,只需要在循环的时候,==将循环次数修改一下就好==。

看一下规律,6个数循环3次,7个数也是换3次;8个数换4次,9个数也换4次。那么就是换数组长度/2次。

因为是/号,所以小数点后的值抹掉。

那么,循环三要素就可以这样写:

for(int i=0;i<array.length/2;i++){ //循环次数-->数组长度/2 -->array.length/2
    
}

然后是循环体部分,看一下规律:

int[] array={1,2,3,4,5,6};
array[0]<--->array[5]
array[1]<--->array[4]
array[2]<--->array[3]
        得到:
array[i]<--->array[5-i] ---> array[(数组长度-1)-i] --> array[(array.length-1)-i]

然后交换元素头尾:

int x=array[i];
array[i]=array[(array.length-1)-i];
array[(array.length-1)-i]=x;

那么循环体加上三要素,循环部分就是这样:

for(int i=0;i<array.length/2;i++){ 
    int x=array[i];
    array[i]=array[(array.length-1)-i];
    array[(array.length-1)-i]=x;
}

这样的话,数组长度变化,结果就会跟着变化。

可以==增强代码的复用性==。

(3)优化代码及执行结果

好啦,最后优化的代码:

public class Test{
    public static void main(String[] args){
        //1.创建数组并初始化
        int[] array={1,2,3,4,5,6};
        //2.循环控制
        for(int i=0;i<array.length/2;i++){ //控制交换次数,数组长度的一半
            int x=array[i];
            array[i]=array[(array.length-1)-i]; //首元素与最后元素互换
            array[(array.length-1)-i]=x;
        }
        //3.输出
         for(int v:array){  
             System.out.println(v); 
         }
    }
}

执行结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nukOtmuS-1658755025563)(D:\Typora图片\image-20220725193736828.png)]

(4)改数组长度

同样,大家可以将数组改一改,再试一试,看看结果。

比如将数组改为四个元素1、2、3、4,然后执行。

public class Test{
    public static void main(String[] args){
        //1.创建数组并初始化
        int[] array={1,2,3,4};
        //2.循环控制
        for(int i=0;i<array.length/2;i++){ //控制交换次数,数组长度的一半
            int x=array[i];
            array[i]=array[(array.length-1)-i]; //首元素与最后元素互换
            array[(array.length-1)-i]=x;
        }
        //3.输出
         for(int v:array){  
             System.out.println(v); 
         }
    }
}

最后结果,就是头尾互换:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Izjwi4oY-1658755025563)(D:\Typora图片\image-20220725193950750.png)]

案例二

01 需求

:car:给定两个数组a{1,2,3,4},b{5,6,7,8},将两个数组内的元素对应位置互换。

02 分析

:cake:下面来剖析一下这个问题。

之前在变量互换的时候,说过三种方式。第一种找中间量互换,第二种利用加和的方式互换,第三种利用异或符号互换。

现在是数组,里面有好多元素,那该如何互换呢?

(1)创建两个数组

根据题意,我们需要先创建两个数组ab

int[] a;
int[] b;

(2)初始化

很明显,题目都已经告诉数组元素了,而且元素个数不是很多,自然用静态初始化啦。

标准写法:

int[] a=new int[]{1,2,3,4};
int[] b=new int[]{5,6,7,8};

简洁写法:

int[] a={1,2,3,4};
int[] b={5,6,7,8};

(3)利用循环控制

元素对应位置的互换。

每个数组,都有四个元素,每一次交换两个数字,一共换四次。

第一次,1和5交换;第二次,2和6互换……

换4次,每次都是做一样的事情。

既然是重复做同一个事情,自然就想到了利用循环解决

①循环三要素

循环一共执行4次,从几开始都可以,之前说过,从1-4可以,从10-13也可以。

但是,如果执行4次,可以和索引号对上,就比较方便。

==索引号也是个变量,如果循环变量和索引号变量变化一致,就会省去一个变量。==

索引号从0开始,那我们可以让循环变量也从0开始。

到什么时候结束?

一共要循环4次,4是元素个数(数组长度),可以用a.length表示。(此时a数组与b数组长度一致)

那么循环三要素就有了。

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

这里的变量i不仅是循环变量,还可以当索引号使用,因为两者变化一致。

②循环体

循环体里面就是写两个数组的对应位置互换元素。

找一下规律:

    a[0]<--->b[0]
    a[1]<--->b[1]
    a[2]<--->b[2]
    a[3]<--->b[3]
        得出:
    a[i]<--->b[i]

规律找出来了,接下来是互换元素。

此时我们发现,a[i]b[i]可以当作两个变量,两个变量互换位置,就是之前学的啦。

这里用中间变量来做示范。

int x=a[i];  //先将a[i]的值存入中间变量x中
a[i]=b[i];    //再将b[i]的值存入a[i]中
b[i]=x;        //最后将x的值存入b[i]中

这里放个大致的图解释一下(基础不好的对照理解哈):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L3l7iTph-1658755025563)(D:\Typora图片\image-20220725144419892.png)]

③整体循环写完了,看一下循环整体代码:

for(int i=0;i<a.length;i++){
    int x=a[i];  
    a[i]=b[i];
    b[i]=x;    
}

(4)输出

分别输出看一下。

这里用增强for循环输出一下,因为这个for循环比较简单。

不知道的戳这里,在数组元素遍历第三点说过,具体位置:

在这里插入图片描述

输出a数组

for(int v:a){    //用变量v来接收数组内的元素,冒号后边是要遍历的数组
    System.out.println(v);
}

输出b数组

for(int v:b){ //用变量v来接收数组内的元素,冒号后边是要遍历的数组
    System.out.println(v); //变量v可以和上边的v重名,因为是两个不同的循环,互不干扰
}

03 代码及执行

(1)代码

加上头尾,整体代码如下:

public class Test{
    public static void main(String[] args){
        //1.创建两个数组
        int[] a={1,2,3,4};
        int[] b={5,6,7,8};
        //2.元素对应位置互换
        for(int i=0;i<a.length;i++){
            int x=a[i];  
            a[i]=b[i];
            b[i]=x;    
        }
        //3.输出
        System.out.println("a数组:");
        for(int v:a){    
                System.out.println(v);
        }
        System.out.println("b数组:");
        for(int v:b){ 
            System.out.println(v); 
        }
    }
}

(2)执行结果

输出看一下结果哈。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uuflup37-1658755025564)(D:\Typora图片\image-20220725151628614.png)]

04 补充

有的小伙伴可能想过用这个方式输出最后交换的数组:

System.out.println(a);
System.out.println(b);

那这个方式对不对呢?

咱们来输出看一下。

整体代码:

public class Test{
    public static void main(String[] args){
        //1.创建两个数组
        int[] a={1,2,3,4};
        int[] b={5,6,7,8};
        //2.元素对应位置互换
        for(int i=0;i<a.length;i++){
            int x=a[i];  
            a[i]=b[i];
            b[i]=x;    
        }
        //3.输出
        System.out.println(a);
        System.out.println(b);
    }
}

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gv56SeBv-1658755025565)(D:\Typora图片\image-20220725150022590.png)]

可以看到,编译时好使的,运行出来的东西是啥?

其实这不是乱码。

这是HashCode码,这里输出的是int类型的整数。(十六进制)

再来想一下数组的内存结构,如int[] a=new int[]{1,2,3,4};

a是在栈内存中的一个内存空间,1,2,3,4存储在堆内存中一个连续的空间里。

a里面存的是一个地址,所以存的地址被经过HashCode计算,得了一串这样的东西。

==@前面表示它的类型,[就是数组类型,I表示数组里面存的是int整数类型;后面是一串经过计算的数字(十六进制)。==

本题,我们是想输出a数组对应位置里边的元素,而不是它的地址。

所以上面的输出方式不可取。

05 延拓

(1)分析拓展

这个题比较简单,但为什么说它呢?

我们会发现,这个题目中,两个数组的长度一致

这就大大降低了题目难度。

如果是这样的两个数组呢?

int[] a={1,2,3,4};
int[] b={5,6,7,8,9,0};

我们想最终换成这样的结果:

int[] a={5,6,7,8,9,0};
int[] b={1,2,3,4};

两个数组长度不一致,就不能跟上面的代码一样了。

若还是上面的那种方式,来想一想。

互换部分的循环若是这样:

//2.元素对应位置互换
        for(int i=0;i<a.length;i++){ //循环4次
            int x=a[i];  
            a[i]=b[i];
            b[i]=x;    
        }

那么就是循环4次,最终a数组的元素就是这样:5,6,7,8。

b数组的元素就是这样:1,2,3,4,9,0。

如果循环部分是这样:

//2.元素对应位置互换
        for(int i=0;i<b.length;i++){ //循环6次
            int x=a[i];  
            a[i]=b[i];
            b[i]=x;    
        }

这样是循环6次,最终a数组的元素就是这样:5,6,7,8。

b数组的元素就是这样:1,2,3,4。

a的长度还不够6个呢,数组越界啦。

(2)举例

那怎么办呢?

①先来分析一下之前两个数组长度相同(元素个数相同)的时候。

来举个小例子吧。

老师甲带班级a,有1号、2号、3号、4号同学;老师乙带班级b,有5号、6号、7号、8号同学。

现在想让老师甲教5号、6号、7号、8号同学,让老师乙教1号、2号、3号、4号同学。

按照刚才的分析,我们是让同学们互换座位

即:1号同学去5号哦同学座位,5号同学去1号同学座位;

2号同学去6号同学座位,6号同学去2号同学座位;

…… ……

具体换座位的细节如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yJx278aX-1658755025565)(D:\Typora图片\image-20220725175356168.png)]

②再来分析一下两个数组长度不相同(元素个数不相同)的时候。

还是拿刚才的例子。

此时,a班级只有四个座位,分别是1、2、3、4;而b班级有6个座位,分别是5、6、7、8、9、0。

老师甲带a班级,老师乙带b班级。

同样,现在想让老师甲教5号、6号、7号、8号、9号、0号同学,让老师乙教1号、2号、3号、4号同学。

按照互换座位的方式是行不通的,因为a班级没有6个座位。

那怎么办呢?

交换老师呗!

让老师甲去b班级,让老师乙去a班级。

(3)分析

:question: 怎么换老师呢?

前提咱们已经了解了数组在内存中的结构啦。

简单回顾一下,然后再来分析。

①还是拿第一个长度相同的两个数组为例。

两个数组:

int[] a={1,2,3,4};
int[] b={5,6,7,8};

循环交换过程:

//2.元素对应位置互换
        for(int i=0;i<a.length;i++){ //循环4次
            int x=a[i];  
            a[i]=b[i];
            b[i]=x;    
        }

来看一下循环交换内存图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JxZmIKHD-1658755025566)(D:\Typora图片\image-20220725181659201.png)]

②第二个长度不相同的两个数组。

两个数组:

int[] a={1,2,3,4};
int[] b={5,6,7,8,9,0};

如果还是按照刚才的循环来存储,上面的就存不下下边六个元素啦。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yODzcuAN-1658755025567)(D:\Typora图片\image-20220725182101165.png)]

数组的存储方式:右边是真实存在的元素,左边是两个地址。

既然刚才试了右边换元素不好使,==那就换左边呗!==

也就是刚才举例的,换老师。

a里面存五角星,那么a就找的是下边的元素;让b里面存三角形,那么b就找的是上边的元素。

也就是老师甲去教b教室学生,老师乙去教a教室学生。不用学生自己挪动座位了。

如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WTMNkmQD-1658755025567)(D:\Typora图片\image-20220725182756848.png)]

(4)解决

按照刚才的分析,循环办法并不是最好的解决方案。

因为它(==交换数组中对应元素==)不仅要循环好多次,还要受长度的限制。

那么接下来的方法(==直接交换变量a和b中的数组引用-->地址==),一次就搞定,不受长度的限制啦。

那么,咱们用交换地址的方式来解决一下。

我们交换两者(星星和三角形),就需要第三方中间变量的加入。以第三方为媒介,互换两者。

三角形和五角星是什么类型的?是int[]数组类型的!

那么我们要创建的中间变量,自然也应该是int[]数组类型的啦!

:soccer: 现在咱们创建int[] temp为中间变量,交换三角形和五角星。

这个交换过程就很容易啦。

int[] temp=a;
a=b;
b=temp;

没有循环,一次搞定。

ab本身是数组类型,里边存的是地址。那么就需要拿一个和它类型匹配的空间来接收 a并充当中间变量。

(5)整体代码及执行结果

①第一个问题(两个数组长度相同)的代码如下:

public class Test{    
    public static void main(String[] args){    
        //1.创建两个数组      
        int[] a={1,2,3,4};       
        int[] b={5,6,7,8};      
        //2.交换变量a和b中的数组引用(地址)  
        int[] temp=a;
        a=b;
        b=temp;
        //3.输出       
        System.out.println("a数组:");     
        for(int v:a){             
            System.out.println(v);     
        }       
        System.out.println("b数组:");    
        for(int v:b){            
            System.out.println(v);       
        }    
    }
}

然后咱们执行看一下结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wR9rynQm-1658755025567)(D:\Typora图片\image-20220725184651900.png)]

和刚才结果一致。


②第二个问题(数组长度不一致)的代码如下:

public class Test{    
    public static void main(String[] args){    
        //1.创建两个数组      
        int[] a={1,2,3,4};       
        int[] b={5,6,7,8,9,0};      
        //2.交换变量a和b中的数组引用(地址)  
        int[] temp=a;
        a=b;
        b=temp;
        //3.输出       
        System.out.println("a数组:");     
        for(int v:a){             
            System.out.println(v);     
        }       
        System.out.println("b数组:");    
        for(int v:b){            
            System.out.println(v);       
        }    
    }
}

然后咱们执行看一下结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uHT8Pzbf-1658755025568)(D:\Typora图片\image-20220725184940194.png)]

看一下代码,我们并未改动其他地方,仅仅==只是改了数组元素==。

由此可见,这个交换数组引用的方法更加完美!

有的小伙伴可能可以写出这个代码,但是不理解我上边说的底层原理,还是不行的哦。

能写出代码,并理解底层原理,才是最重要的!

三、叨叨

这次的小练习,还是很简单,但我想告诉大家,要沉下心,不能盲目刷题。

每一个题目,也许你会很快解决,但是,是不是最优解呢?是不是底层原理都知道呢?

相遇即是缘,希望我的文章对你有帮助~

如果有什么不对的地方,欢迎指正~

在这里插入图片描述

相关文章
|
4天前
|
存储 Java 程序员
Java 数组
4月更文挑战第16天
|
26天前
|
Java
java 8 数组转字符串并以逗号分隔
java 8 数组转字符串并以逗号分隔
11 0
|
1月前
|
Java
【Java】数组中的拷贝方法与初步理解深浅拷贝
【Java】数组中的拷贝方法与初步理解深浅拷贝
12 0
|
1月前
|
存储 Java C语言
【Java】以数组为例简单理解引用类型变量
【Java】以数组为例简单理解引用类型变量
14 1
|
1月前
|
存储 Java 索引
Java数组
Java数组
7 0
|
1月前
|
Java
java中判断数组中元素出现的次数
java中判断数组中元素出现的次数
10 0
|
1月前
|
Java
java向数组中插入元素
java向数组中插入元素
9 0
|
1月前
|
存储 Java 索引
JAVA一维数组
JAVA一维数组
19 3
|
1月前
|
Java 索引
JAVA数组的常用方法
JAVA数组的常用方法
17 1
|
1月前
|
Java C语言
Java中的数组,你知道多少细节?
Java中的数组,你知道多少细节?
26 1