JAVA中对数组的理解及数组经典例题详解

目录

  • 前言
  • 一、创建数组
    • 创建数组的三种方式
  • 二、 数组的使用
    • 1.获取长度 & 访问元素
    • 2.遍历数组
      • 2.1使用for循环
      • 2.2使用for each循环
      • 2.3Arrays类的toString 方法
  • 三、数组作为方法的参数
    • 3.1打印数组的内容
    • 3.2理解引用类型
    • 3.3认识null
    • 3.4 初识 JVM 内存区域划分
  • 四、数组作为方法的返回值
  • 五、数组练习
    • 5.1 数组转字符串
    • 5.2 找数组中的最大元素
    • 5.3 求数组中元素的平均值
    • 5.4 查找数组中指定元素(顺序查找)
    • 5.5 查找数组中指定元素(二分查找)
    • 5.6检查数组的有序性
    • 5.7数组排序(冒泡排序)
    • 5.8数组逆序
    • 5.9数组数字排列
    • 5.10数组的拷贝
      • 5.10.1 用克隆的方法直接拷贝一个新的数组
      • 5.10.2用 System.arraycopy()方法进行拷贝
      • 5.10.3用Arrays.copyOf()的方法进行拷贝
      • 5.10.4 Arrays.copyOfRange()拷贝数组中得指定长度
      • 5.10.5 Arrays.fill()数组的填充
  • 六、二维数组
    • 6.1二维数组定义的三种方式
    • 6.2二维数组的遍历
    • 6.3不规则的二维数组

前言

数组是一种数据结构,用来存储同一类型值的集合。通过一个整型下标可以访问数组中的每一个值。例如:如果a是一个整型数组,a[i]就是数组中下标为i的整数。在声明数组变量时,需要指出数组类型(数据元素类型紧跟[]和数组变量的名字。下面声明了整型数组a:int[]a;这条语句只声明了变量a,并没有将a初始化为一个真正的数组。应该使用new运算符创建数组。int[] a = new int[100];
这条语句创建了一个可以存储100个整数的数组。数组长度不要求是常量: new int[n]会创建一个长度为n的数组。

一、创建数组

数组本质上就是让我们能 “批量” 创建相同类型的变量。在 Java 中, 数组中包含的变量必须是相同类型

创建数组的三种方式

方式一:

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

方式二:

int[] arr2 = new int[3];//定义数组长度为3,未初始化

方式三:

int[] arr3 = new int[]{
     1,2,3,4,5};//定义数组长度为5,初始化

二、 数组的使用

1.获取长度 & 访问元素

 public static void main(String[] args) {
     
        int[] arr = {
     1,2,3,4,5};
        System.out.println(arr.length);//求数组的长度
        System.out.println(arr[3]);//访问数组中的元素
        arr[3] = 19;
        System.out.println(arr[3]);//改变数组里面的内容
 }

注意:

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

2.遍历数组

“遍历” 是指将数组中的所有元素都访问一遍, 不重不漏. 通常需要搭配循环语句.

2.1使用for循环

for循环可以拿到下标

 public static void main(String[] args) {
     
        int[] arr = {
     1,2,3,4,5};
        for (int i = 0; i < arr.length; i++) {
      //for循环可以拿到下标
        System.out.print(arr[i] + " "); //打印数组中的每个元素
        }

2.2使用for each循环

语法格式:

for (int element : a)
System.out.println(element);

打印数组a的每一个元素,一个元素占一行。这个循环应该读作“循环a中的每一个元素”( for each element in a)。Java语言的设计者认为应该使用诸如foreach、in这样的关键字,但这种循环语句并不是最初就包含在Java语言中的,而是后来添加进去的,并且没有人打算废除已经包含同名(例如System.in)方法或变量的旧代码。
for each循环又称增强for循环,可以打印数组中的每个元素 但是拿不到数组下标

  public static void main(String[] args) {
     
        int[] arr = {
     1,2,3,4,5};
        for (int x:arr) {
       //
            System.out.print(x + " ");
        }

2.3Arrays类的toString 方法

调用Arrays.toString(a),返回一个包含数组元素的字符串,这些元素被放置在括号内,并用逗号分隔,例如:“[2,3,5,7,11,13]”。要想打印数组,可以调用:System.out.println(Arrays.toString(a));

 public static void main(String[] args) {
     
        int[] arr = {
     1,2,3,4,5};
//借助java的操作数组的工具类  Arrays.toString:将参数的数组以字符串的形式进行输出
        String ret = Arrays.toString(arr);
        System.out.println(ret);
    }

三、数组作为方法的参数

3.1打印数组的内容

 public static void printf(int[] a) {
     
        for (int i = 0; i < a.length; i++) {
     
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
    public static void main(String[] args) {
     
        int[] arr = {
     1,2,3,4,5};
        printf(arr);//按引用传递(按值传递)
    }

在这个代码中int[] a 是函数的形参, int[] arr 是函数实参.

3.2理解引用类型

  public static void func1(int[] arr){
     
        arr = new int[]{
     10,12,24,52,61};
    }
    public static void func2(int[] arr){
     
        arr[0] = 521;
    }
    public static void main(String[] args) {
     
        int[] arr = {
     1,2,3,4,5};
        System.out.print(Arrays.toString(arr));// 1,2,3,4,5
        System.out.println();
  //    func1(arr);//1,2,3,4,5 虽然传的是地址,但是传过去之后,形参只是改变了自己的指向而已。
        func2(arr); //521,2,3,4,5
//在函数内部修改数组内容, 函数外部也发生改变.此时数组名 arr 是一个"引用".当传参的时候, 是按照引用传参.
        System.out.print(Arrays.toString(arr));
    }

所谓的 “引用” 本质上只是存了一个地址. Java 将数组设定成引用类型, 这样的话后续进行数组参数传参, 其实只是将数组的地址传入到函数形参中. 这样可以避免对整个数组的拷贝(数组可能比较长, 那么拷贝开销就会很大).

3.3认识null

 public static void main4(String[] args) {
     
        int[] arr = {
     1,2,3,4,5};
        int[] arr2 = null;//代表这个引用不指向任何对象
        System.out.println(arr2);//空指针异常
    }

null 的作用类似于 C 语言中的 NULL (空指针), 都是表示一个无效的内存位置。因此不能对这个内存进行任何读写操作。 一旦尝试读写, 就会抛出:NullPointerException.
注意: Java 中并没有约定 null0 号地址的内存有任何关联。

3.4 初识 JVM 内存区域划分

JVM 的内存被划分成了几个区域:

  1. 程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址.
  2. 虚拟机栈(JVM Stack): 重点是存储局部变量表(当然也有其他信息). 我们刚才创建的 int[] arr 这样的存储地址的引用就是在这里保存.
  3. 本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量. 在有些版本的JVM实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的.
  4. 堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} ).
  5. 方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域.
  6. 运行时常量池(Runtime Constant Pool): 是方法区的一部分, 存放字面量(字符串常量)与符号引用. (注意 从 JDK1.7 开始, 运行时常量池在堆上).

Native 方法:
JVM 是一个基于 C++ 实现的程序. 在 Java 程序执行过程中, 本质上也需要调用 C++ 提供的一些函数进行和操作系统底层进行一些交互. 因此在 Java 开发中也会调用到一些 C++ 实现的函数.这里的 Native 方法就是指这些 C++ 实现的, 再由 Java 来调用的函数.

四、数组作为方法的返回值

写一个方法, 将数组中的每个元素都 * 2

/**
     * 在原来的数组上扩大2倍
     * @param arr
     */
    public static void func(int[] arr){
     
        for (int i = 0; i < arr.length; i++) {
     
            arr[i] = 2 * arr[i];
            System.out.print(arr + " ");
        }
    }
    /**
     * 不改变原数组,将数组扩大2倍,创建一个新的数组用来接收扩大2倍之后的值
     * @param arr
     * @return
     */
    public static int[] func3(int[] arr){
     
        int[] ret = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
     
            ret[i] = 2 * arr[i];
        }
        return ret;
    }
    public static void main9(String[] args) {
     
        int[] arr = {
     1,2,3,4,5};
        func(arr);
        int[] ret2 = func3(arr);
        System.out.print(Arrays.toString(ret2));

    }

五、数组练习

5.1 数组转字符串

 /**
     * 写一个方法将数组转字符串
     * @param arr
     * @return
     */
    public static String myToString(int[] arr){
     
        if(arr == null){
     
            return null;
        }
        String ret = "[";
        for (int i = 0; i < arr.length; i++) {
     
            ret += arr[i];
            if(i != arr.length - 1){
     
                ret += ",";
            }
        }
        ret += "]";
        return ret;
    }
    public static void main10(String[] args) {
     
        int[] arr = {
     1,2,3,4,5};
        System.out.println(myToString(arr));
    }

利用java所提供的Arrays包,也可以实现数组转字符串操作:

import java.util.Arrays
int[] arr = {
     1,2,3,4,5,6};
String newArr = Arrays.toString(arr);
System.out.println(newArr);//[1, 2, 3, 4, 5, 6]

5.2 找数组中的最大元素

 public static void main(String[] args) {
     
int[] arr = {
     1,2,3,4,5,6};
System.out.println(maxNum(arr));
}
 public static int maxNum(int[] arr){
     
        if(arr == null){
     
            return -1;
        }
        if(arr.length == 0){
     
            return -1;
        }
        int max = arr[0];
        for (int i = 0; i < arr.length; i++) {
     
            if(max < arr[i]){
     
                max = arr[i];
            }
        }
        return max;
    }

5.3 求数组中元素的平均值

 public static double avg(int[] arr){
     
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
     
            sum += arr[i];
        }
        return (double) sum/(double) arr.length;
    }
    public static void main(String[] args) {
     
        int[] arr = {
     1,2,3,4,5,6};
        System.out.println(avg(arr));

    }

5.4 查找数组中指定元素(顺序查找)

给定一个数组, 再给定一个元素, 找出该元素在数组中的位置,返回数组的下标。

 public static int findNum(int[] arr,int key){
     
        for (int i = 0; i < arr.length; i++) {
     
            if(arr[i] == key){
     
                return i;
            }
        }
        return -1;
    }
 public static void main11(String[] args) {
     
        int[] arr = {
     4,5,2,8,44,2,0};
        System.out.println(findNum(arr,8));
    }

5.5 查找数组中指定元素(二分查找)

以升序数组为例, 二分查找的思路是先取中间位置的元素, 看要找的值比中间元素大还是小. 如果小, 就去左边找; 否则就去右边找。

 public static int binarySearch(int[] arr,int k){
     
        int l = 0;
        int r = arr.length - 1;
        while (l < r){
     
            int mid = (l + r)/2;
            if(arr[mid] > k){
     
                r = mid - 1;
            }
            else if(arr[mid] < k){
     
                l = mid + 1;
            }
            else
                return mid;
        }
        return -1;
    }
    public static void main11(String[] args) {
     
        int[] arr = {
     1,2,3,4,5,78,99};
        System.out.println(binarySearch(arr,78));
        System.out.println(Arrays.binarySearch(arr, 78)); //自带的二分查找
    }

5.6检查数组的有序性

public static void main(String[] args) {
     
	int[] arr = {
     1,2,3,10,5,6};
	System.out.println(isSorted(arr));
} 
public static boolean isSorted(int[] arr) {
     
	for (int i = 0; i < arr.length - 1; i++) {
     
	if (arr[i] > arr[i + 1]) {
     
	return false;
	}
} 
	return true;
}

5.7数组排序(冒泡排序)

 public static void main(String[] args) {
     
        int[] arr = {
     3,5,6,1,2,9,0,8,4,7};
        boolean flg = false;
        for (int i = 0; i < arr.length; i++) {
     
            for (int j = arr.length - 1; j > i; j--) {
     
                if(arr[j] < arr[j - 1]){
     
                    int temp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = temp;
                    flg = true;
                }
            }
            if(flg == false){
     
                return;//break;
            }
        }
        System.out.println(Arrays.toString(arr));
    }

加上flg之后,如果数组在排序途中已经有序,可提前结束循环。

冒泡排序性能较低. Java 中内置了更高效的排序算法:

public static void main(String[] args) {
     
	int[] arr = {
     9, 5, 2, 7};
	Arrays.sort(arr);
	System.out.println(Arrays.toString(arr));
}

5.8数组逆序

给定一个数组, 将里面的元素逆序排列.
思路:设定两个下标, 分别指向第一个元素和最后一个元素. 交换两个位置的元素.
然后让前一个下标自增, 后一个下标自减, 循环继续即可.

public static void main(String[] args) {
     
	int[] arr = {
     1, 2, 3, 4};
	reverse(arr);
	System.out.println(Arrays.toString(arr));
} 
public static void reverse(int[] arr) {
     
	int left = 0;
	int right = arr.length - 1;
	while (left < right) {
     
	int tmp = arr[left];
	arr[left] = arr[right];
	arr[right] = tmp;
	left++;
	right--;
	}
}

5.9数组数字排列

给定一个整型数组, 将所有的偶数放在前半部分, 将所有的奇数放在数组后半部分.
思路:设定两个下标分别指向第一个元素和最后一个元素.用前一个下标从左往右找到第一个奇数, 用后一个下标从右往左找到第一个偶数, 然后交换两个位置的元素.依次循环即可.


public static void main(String[] args) {
     
	int[] arr = {
     1, 2, 3, 4, 5, 6};
	transform(arr);
	System.out.println(Arrays.toString(arr));
} 
public static void transform(int[] arr) {
     
	int left = 0;
	int right = arr.length - 1;
	while (left < right) {
     
	// 该循环结束, left 就指向了一个奇数
	while (left < right && arr[left] % 2 == 0) {
     
		left++;
	} 
	// 该循环结束, right 就指向了一个偶数
	while (left < right && arr[right] % 2 != 0) {
     
		right--;
} 
// 交换两个位置的元素
	int tmp = arr[left];
	arr[left] = arr[right];
	arr[right] = tmp;
	}
}

5.10数组的拷贝

5.10.1 用克隆的方法直接拷贝一个新的数组

  public static void main(String[] args) {
     
        int[] arr = {
     11,12,13,45,56};
        int[] copy = arr.clone();
        System.out.println(Arrays.toString(copy));
    }

5.10.2用 System.arraycopy()方法进行拷贝

 public static void main(String[] args) {
     
      int[] arr = {
     11,12,13,45,56};    
      int[] copy = new int[arr.length];
      System.arraycopy(arr,0,copy,0,arr.length);
      //arr表示原数组,0表示原数组拷贝的起始地址,copy表示目的数组,0表示目的数组的
      //起始位置,arr.length表示要拷贝的数组的长度
      System.out.println(Arrays.toString(copy));
 }        					
 System.arraycopy(arr,0,copy,0,arr.length);
  //arr表示原数组,0表示原数组拷贝的起始地址,copy表示目的数组,0表示目的数组的
  //起始位置,arr.length表示要拷贝的数组的长度

5.10.3用Arrays.copyOf()的方法进行拷贝

5.10.4 Arrays.copyOfRange()拷贝数组中得指定长度

 public static void main(String[] args) {
     
        int[] arr = {
     11,12,13,45,56};
        //可以拷贝数组的长度,也可以拷贝数组长度的整数倍,
        //拷贝其整数倍之后,后面的值如果不赋初值,其默认都为0.
        int[] ret = Arrays.copyOf(arr,arr.length * 2);
       //也可以用Arrays.copyOfRange()拷贝数组中得指定长度 
       int[] ret1 = Arrays.copyOfRange(arr,1,3);
        System.out.println(Arrays.toString(ret));
       System.out.println(Arrays.toString(ret1));

5.10.5 Arrays.fill()数组的填充

  public static void main(String[] args) {
     
  //定义一个数组长度为10的一维数组
       int[] arr = new int[10];
       //长度为10的一维数组中的所有元素都填充为99
       Arrays.fill(arr,99);  //填充
         //一维数组中的指定下标元素填充为99
       Arrays.fill(arr,2,6,99);
       //System.out.println(Arrays.toString(arr));

    }

六、二维数组

二维数组本质上也就是一维数组, 只不过每个元素又是一个一维数组.
语法格式:

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

6.1二维数组定义的三种方式

  int[][] arr1 = {
     {
     1,2,3},{
     4,5,6}};
  int[][] arr2 = new int[][]{
     {
     1,2,3},{
     4,5,6}};
  int[][] arr3 = new int[2][3];

6.2二维数组的遍历

public static void main(String[] args) {
     
		int[][] arr = {
     
		{
     1, 2, 3, 4},
		{
     5, 6, 7, 8},
		{
     9, 10, 11, 12}
		};
}
//二维数组的打印,方法1:
 for (int i = 0; i < arr.length; i++) {
     
       for (int j = 0; j < arr[i].length; j++) {
     
          System.out.print(arr[i][j] + " ");
	} 
	 System.out.println();//换行
	 System.out.println("******************");
//二维数组的打印,方法2:
        for (int[] ret:arr) {
     
            for (int x:ret) {
     
                System.out.print(x+" ");
            }
            System.out.println();
        }
        System.out.println("******************");
//二维数组的打印,方法3:Arrays里面自带的包打印数组     
        System.out.println(Arrays.deepToString(arr));
}

6.3不规则的二维数组

如果二维数组里面的数字没有全部写完,则打印出来的二维数组相应位置是个空格,而不是0
如果二维数组的列没有写,可以对它的列重新赋值。

 public static void main5(String[] args) {
     
        int[][] arr1 = {
     {
     1,2},{
     4,5,6}};
        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();
        }
        System.out.println("*****************");
        //不规则的二维数组
        int[][] arr3 = new int[2][];
        arr3[0] = new int[3];
        arr3[1] = new int[2];
        for (int i = 0; i < arr3.length; i++) {
     
            for (int j = 0; j < arr3[i].length; j++) {
     
                System.out.print(arr3[i][j] + " ");
            }
            System.out.println();
        }
    }

以上。

你可能感兴趣的:(编程,基础知识,JAVA,java,开发语言,intellij-idea)