7.1 定义以及初始化数组
7.1.1 认识数组
在编程当中,很多时候我们需要使用到许多同类型的数据。如果数量较多的话,程序会显得较为笨重。例如:
- class ArrayDemo {
- public static void main(String[] args) {
- int num1 = 3;
- int num2 = 2;
- int num3 = 7;
- int num4 = 5;
- int num5 = 4;
- }
- }
在这个例子当中,有大量的int类型数据重复。程序显得没有弹性,臃肿。数组就是用来解决这个问题。数组是一个可以储存若干个同类型数据的类型。
在Java中,数组并非一个类,而是一个特殊的引用类型数据。现在我们来学习如何定义一个数组。
7.1.2 定义数组
定义数组的语法如下:
- 数组类型[] 数组名;
- 数组类型 数组名 [];
我们现在来定义一个可以存储int类型的数组。
- int[] arr;
好的,这个部分很简单。但是我们现在的数组还没有值,我们需要初始化这个数组。请看下一节。
7.1.3 动态初始化
动态初始化是只指定数组的长度,而不对其的元素进行设置。元素的值会是其对应的类型的默认值。
语法如下:
- 数组类型 数组名 = new 数组类型[数组长度];
在Java中,通过以下语法访问数组中的元素:
- 数组名[下标]
下标从0开始。
好的,现在我们来定义一个int类型数组,对其的值进行赋值。
- class ArrayDemo {
- public static void main(String[] args) {
- int arr[] = new int[5]; //定义并动态初始化int类型数组,将其长度设置为5
- //访问数组元素,并赋值
- arr[0] = 2;
- arr[1] = 4;
- arr[2] = 1;
- arr[3] = 7;
- arr[4] = 6;
-
- //逐个打印数组元素
- System.out.println(arr[0]+","+arr[1]+","+arr[2]+","+arr[3]+","+arr[4]);
- }
- }
在这个例子当中,我们可以发现,动态初始化的方式需要我们手动的对数组中的每一个元素进行赋值。动态初始化的数组的元素全部为其对应的类型的默认值,例如int类型的默认值是0,int类型的数组动态初始化后其中所有的元素都为0。
那么,有没有一个初始化方法,在初始化的时候就已经把元素的值确定下来的呢?
7.1.4 静态初始化
静态初始化可以在定义数组时就将其的元素全部赋值好。语法如下:
- 数组类型 数组名 = new 数组类型[]{元素值1,元素值2,元素值3,.....元素值n};
- 数组类型 数组名 = {元素值1,元素值2,元素值3,.....元素值n};
- class ArrayDemo {
- public static void main(String[] args) {
- int[] arr = {2,4,1,7,6}; //静态初始化
- System.out.println(arr[0]+","+arr[1]+","+arr[2]+","+arr[3]+","+arr[4]); //打印元素
- }
- }
这种方式比上一中的简便多了。但是如果在编程的时候的确在定义数组时其值不确定,可以动态初始化。
数组还有一个特点,一经初始化,长度无法改变。
学生提问:数组可以存储引用类型数据吗?
答:可以。例如我一个数组也可以用来存String类的数据。例如:
复制代码
- String[] arr = {"abc","def"};
本章小结
- 数组是一个储存若干个同类型数据的类型
- 数组的定义方式为“数组类型 数组名”
- 动态初始化语法为“数组类型 数组名 = new [长度]”
- 静态初始化语法为“数组类型 数组名 = {元素值1,元素值2,元素值3,.....元素值n}”
- 访问数组元素的方式为“数组名[下标]”
7.2 遍历数组以及foreach
7.2.1 遍历数组概念
遍历数组可以理解获取数组中的每一个元素,一般是打印、判断等。我们可以通过传统的for循环,以及较新的foreach方式来遍历。
7.2.2 数组的length字段
在通过for遍历数组时,需要获取数组的长度来提供循环条件。所以在学遍历之前先学一下length字段。
length很容易理解,就是数组的长度。
- class ArrayDemo {
- public static void main(String[] args) {
- int[] arr = {2,4,1,7,6};
- System.out.println(arr.length);
- }
- }
在这个例子中,arr一共有五个元素。打印length字段则为5。相信很容易理解。
7.2.3 for遍历
for遍历一般先定义一个整数类型,判断条件是让这个整数类型与数组长度进行比较。实例如下:
- class ArrayDemo {
- public static void main(String[] args) {
- int[] arr = {2,4,1,7,6};
- for(int x = 0;x<arr.length;x++){
- System.out.print(arr[x]+",");
- }
- }
- }
for循环中定义了变量x,循环条件是其是否小于数组的长度。循环体中打印arr的x下标元素。为了不让其换行,使用了print()方法而不是println()方法。
不过有一个小问题,打印最后一个元素时也有一个逗号。我们可以判断x是否为最后一个元素,然后进行输出。
- class ArrayDemo {
- public static void main(String[] args) {
- int[] arr = {2,4,1,7,6};
- for(int x = 0;x<arr.length;x++){
- if(arr.length-1==x){
- System.out.print(arr[x]);
- }
- else{
- System.out.print(arr[x]+",");
- }
- }
- }
- }
每次循环中判断x是否等于length-(至于为什么-1是因为下标是从0开始的),然后进行对应的打印输出。
7.2.4 foreach
foreach是一种更加简便的遍历方式,但是其不是一个关键字,在使用时用到的关键字仍然是for。语法如下:
- for(整数类型 变量名:数组){
- //遍历语句
- }
引用我们的例子,我们可以这样写:
- class ArrayDemo {
- public static void main(String[] args) {
- int[] arr = {2,4,1,7,6};
- for(int x:arr){
- System.out.println(x);
- }
- }
- }
这种写法更加方便,比较推荐大家使用。
本章小结
- 遍历是指获取数组中的每一个元素
- for可以用来遍历
- foreach是一个更加简便的遍历方法
7.3 获取最值算法
7.3.1 算法概述
Java并没有为我们提供数组最值的方法。所以说如果要获取数组中的最大值/最小值,需要我们自己去写一个小工具。这一节我们就来介绍一下算法。
算法其实很简单,就是遍历数组中的每一个元素,用一个变量来记住元素的值。如果第n个元素比第n-1个元素大,用这个变量记住第n个元素即可。最小值同理。
7.3.2 实现算法
既然要遍历,肯定要用到for。而且需要定义一个变量来记住最值(这里先示范最大值),将这个变量初始化为数组的第一个元素。
- public static int getMax(int[] arr){
- int max = arr[0];
- for(int element = 1;element<arr.length;element++){
-
- }
- }
- public static int getMax(int[] arr){
- int max = arr[0];
- for(int element = 1;element<arr.length;element++){
- if(arr[element]>max){
- max = arr[element];
- }
- }
- }
学生提问:为什么不用foreach?
答:因为在foreach中定义的变量的初始值肯定为0,不能是1。然而第0个下标元素和自己比较是没有意义的。如果要用foreach也可以,只不过多了一个不需要的比较罢了。
最后,我们再把max返回即可。
- public static int getMax(int[] arr){
- int max = arr[0];
- for(int element = 1;element<arr.length;element++){
- if(arr[element]>max){
- max = arr[element];
- }
- }
- return max;
- }
- class GetMaxDemo {
- public static void main(String[] args) {
- int[] arr = {4,8,6,1,2,5};
- System.out.println(getMax(arr));
- }
-
- public static int getMax(int[] arr){
- int max = arr[0];
- for(int element = 1;element<arr.length;element++){
- if(arr[element]>max){
- max = arr[element];
- }
- }
- return max;
- }
- }
如果要判断最小值,把if中的判断语句改成小于即可。
本章小结
- 通过对元素的遍历记住最大值并返回即可
- 也可以用foreach,只是多了一次无意义的比较而已
7.4 Arrays类
7.4.1 binarySearch()方法
Arrays类是Java为我们提供的数组工具类,其中的许多方法都十分常用,而且都为static,所以可以直接被类调用。
binarySearch()通过折半查找算法,在数组中查找指定的值,并返回角标。其有多个方法被重载。其接收两个参数:第一个参数是一个数组引用,不同的方法接收不同类型的数组;第二个参数是要查找的元素的值。
不过要注意:由于Arrays类在java.util包下,需要导包。这点我们在面向对象(下)中会学到。在这里大家就先把这行代码加在程序的第一行:
- import java.util.Arrays;
上整个实例的代码:
- import java.util.Arrays;
- class ArraysDemo {
- public static void main(String[] args) {
- int[] arr = {2,5,3,7,5,4};
- System.out.println("3在arr数组中的角标为"+Arrays.binarySearch(arr, 3));
- }
- }
3在数组中为第三个元素,对应的下标就是2。通过binarySearch()方法,传入arr数组以及要查找的值3,其将返回其所在的角标。
如果没有找到这个值,返回一个负数。
7.4.2 equals()方法
equals()方法接收两个同类型的数组,返回值为boolean类型。如果两个数组的长度一样,而且元素值也一样,返回true;反之亦然。
- import java.util.Arrays;
- class ArraysDemo {
- public static void main(String[] args) {
- int[] arr = {2,5,3,7,5,4};
- int[] arr2 = {2,5,3,7,5,4};
- System.out.println("arr和arr2是否相等?"+Arrays.equals(arr, arr2));
- }
- }
- import java.util.Arrays;
- class ArraysDemo {
- public static void main(String[] args) {
- int[] arr = {2,5,3,7,5,4};
- int[] arr2 = {2,5,3,7,5,4,1};
- System.out.println("arr和arr2是否相等?"+Arrays.equals(arr, arr2));
- }
- }
7.4.3 sort()方法
sort()方法无返回值,接收数值类型的数组,以及引用类型数组。对于数值类型数组,使用sort()方法会对其进行排序(从小到大);sort()方法也可以接收引用类型数组,但是我们先不讲。
- import java.util.Arrays;
- class ArraysDemo {
- public static void main(String[] args) {
- int[] arr = {43,23,36,64,15};
- Arrays.sort(arr); //排序数组
- for(int x = 0;x<arr.length;x++){ //遍历排序之后的数组
- if(x==(arr.length-1)){
- System.out.print(arr[x]);
- }
- else{
- System.out.print(arr[x]+",");
- }
- }
- }
- }
arr数组原本是无序的一个int类型数组。通过sort()方法排序之后,在进行遍历打印输出,可以发现其中的元素被从小到大排序了。
7.4.4 toString()方法
toString()方法用于将数组转换成一个字符串的表达形式。
- import java.util.Arrays;
- class ArraysDemo {
- public static void main(String[] args) {
- int[] arr = {43,23,36,64,15};
- System.out.println(Arrays.toString(arr));
- }
- }
这个方法十分方便。以后都不需要遍历数组来打印输出了,直接转换成字符串打印输出即可。
本章小结
- binarySearch()通过折半查找算法返回指定的元素值的下标
- equals()方法返回布尔,用于比较两个同类型数组元素知否完全一样
- sort()方法用于排序数组
- toString()用于将数组转换成字符串表达形式
7.5 两种排序算法
7.5.1 选择排序
虽说Arrays类已经给我们提供了sort()方法对数组进行排序,但是为了让我们对算法更多地了解,我们还是来手写几个排序的算法。
选择排序是一个很简单的排序算法。这种算法很容易理解,但是不太稳定。我们先从这个算法入手吧。
在排序的第一轮:[0]要和[1]相比较,如果[0]>[1],两者交换位置;然后[0]要和[2]比较,如果[0]>[2],交换。以此类推,直到比较到最后一个元素。
在排序的第二轮:[1]要和[2]相比较,然后比较[1]和[3]...以此类推
在排序的第三轮:[2]要和[3]相比较,然后比较[2]和[4]...以此类推。
以此类推...
大家可以发现一个规律:在第n轮中,第n-1个角标不需要参与运算。
一共需要比较n-1次(n为数组长度)。现在我们用代码来实现吧!
首先我们知道要比较n-1次,所以我们来写一个for循环:
- public static int[] selectionSort(int[] arr){
- for(int x = 0;x<arr.length;x++){
-
- }
- }
在每一轮中,我们需要让相邻的两个角标比较。由于“在第n轮中,第n-1个角标不需要参与运算”,我们定义内部for的变量时可以初始化为x+1。
- public static int[] selectionSort(int[] arr){
- for(int x = 0;x<arr.length;x++){
- for(int y = x+1;y<arr.length;y++){
- if(arr[y]<arr[y-1]){
-
- }
- }
- }
- }
在内部的for循环中,如果[y]<[x],那么就要交换两个值。那么如何交换呢?
首先我们需要第三个值来记住[y],然后把arr[x]赋给[y],最后把temp赋给[x]。
- public static int[] selectionSort(int[] arr){
- for(int x = 0;x<arr.length;x++){
- for(int y = x+1;y<arr.length;y++){
- if(arr[y]<arr[x]){
- int temp = arr[y];
- arr[y] = arr[x];
- arr[x] = temp;
- }
- }
- }
- }
而且最后把arr返回即可。
- public static int[] selectionSort(int[] arr){
- int temp;
- for(int x = 0;x<arr.length-1;x++){
- for(int y = x+1;y<arr.length;y++){
- if(arr[y]<arr[x]){
- temp = arr[y];
- arr[y] = arr[x];
- arr[x] =temp;
- }
- }
- }
- return arr;
- }
ok,现在这个方法写完了,我们在主方法中测试一下。
- import java.util.Arrays;
- public class ArraySort {
- public static void main(String[] args) {
- int[] arr = {3,5,4,2,5,7};
- int[] newArr = selectionSort(arr);
- System.out.println(Arrays.toString(newArr));
- }
- public static int[] selectionSort(int[] arr){
- for(int x = 0;x<arr.length;x++){
- for(int y = x+1;y<arr.length;y++){
- if(arr[y]<arr[x]){
- int temp = arr[y];
- arr[y] = arr[x];
- arr[x] =temp;
- }
- }
- }
- return arr;
- }
- }
可以发现,[3,5,4,2,5,7]数组被排序成了[2,3,4,5,5,7]。这个算法就写完了。
7.5.2 冒泡排序
冒泡排序同样是一个很容易理解的排序算法。
第一轮:[0]和[1]比较,如果[0]>[1]替换,然后比较[1]和[2],比较[2]和[3]...[n-1]和[n]
第二轮:从[0]和[1]比较到[n-2]和[n-1]
第三轮:从[0]和[1]比较到[n-3]和[n-2]
第m论:从[0]到[1]比较到[n-m]和[n-m+1]
这个算法最大的特点就是每一轮较大的值都会满满地“浮”到最后,因此命名冒泡排序。
最坏的情况也是一共需要比较n-1轮。
通过代码实现:
首先定义一个for循环,这个选择排序一模一样:
- public static int[] bubbleSort(int[] arr){
- for(int x = 0;x<arr.length;x++){
-
- }
- }
- public static int[] bubbleSort(int[] arr){
- for(int x = 0;x<arr.length;x++){
- for(int y = 0;y<arr.length-x-1;y++){
-
- }
- }
- }
那么为什么要-1呢?假设内部for已经是最后一次循环了,也就是说y=arr.length-x,如果要比较[y]和[y+1],[y+1]就角标越界了。为了防止越界,对其-1即可。
接下来就是比较和交换了:
- public static int[] bubbleSort(int[] arr){
- int temp;
- for(int x = 0;x<arr.length;x++){
- for(int y = 0;y<arr.length-x-1;y++){
- temp = arr[y];
- arr[y] = arr[y+1];
- arr[y+1] = temp;
- }
- }
- return arr;
- }
- import java.util.Arrays;
- public class ArraySort {
- public static void main(String[] args) {
- int[] arr = {6,5,4,3,2,1};
- int[] newArr = bubbleSort(arr);
- System.out.println(Arrays.toString(newArr));
- }
-
- public static int[] bubbleSort(int[] arr){
- int temp;
- for(int x = 0;x<arr.length;x++){
- for(int y = 0;y<arr.length-x-1;y++){
- temp = arr[y];
- arr[y] = arr[y+1];
- arr[y+1] = temp;
- }
- }
- return arr;
- }
- }
本章小结:
- 数组中有两个常用的排序算法:选择排序和冒泡排序
- 在交换两个值的时候,要使用第三个值对其中的一个值进行缓存
- 不推荐在循环当中定义类型
7.6 二维数组
7.6.1 二维数组的定义
数组可以用来储存同一个类型的若干个数据。但是现在我们遇到的问题就是里面存的数据还是一个数组,可以理解为“一个数组包含多个数组”。
二维数组的定义方式如下:
- 数据类型[][] 数组名;
例如:
- int[][] array;
7.6.2 二维数组的动态和静态初始化
其实二维数组的两种初始化方法和一维数组也差不多。
动态初始化语法:
- 数据类型[][] 数组名 = new int[行][列];
- 数组类型[][] 数组名 = {第一个数组,第二个数组,第三个数组....,第四个数组};
访问数组中的元素:
- 数组名[行][列]
7.6.3 二维数组遍历
对于二维数组的遍历,需要使用到双层嵌套for:
- int[][] array = {{2,3},{4,2},{5,6},{3,7}};
-
- for(int x = 0;x<array.length;x++){
- for(int y = 0; y<array[x].length;y++){
- if(x==array.length-1 && y==array[x].length-1){
- System.out.print(array[x][y]);
- }
- else{
- System.out.print(array[x][y]+",");
- }
- }
- }
在外部的for当中,判断条件是x是否小于array.length。这个不难理解。
但是内部循环中,判断条件是y是否小于array的第x个角标元素的length。由于二维数组中的元素还是数组,所以可以对其的元素调用length方法。
内部的if else语句也需要说明一下。首先,如果已经遍历到了最后一个元素,而且是最后一个元素的最后一个元素,才可以输出的时候不带逗号,否则需要逗号。
本章小结
- 二维数组的元素是数组
- 二维数组的定义和初始化和一维数组差不多
- 遍历二维数组需要使用嵌套for循环