Java-3-Array

Introduction

这一章介绍Java 里面的Array数组的操作和原理。 这里会先简单介绍一下数组的概念和以及数组的基本操作(创建,遍历修改,排序,更加高维度的数组的操作等)

1. 数组基本概念 Concept

1.1 什么是数组

首先什么是数组? 数组是一种数据结构不管在哪种编程语言都会用到, 它就好比是我们的有很多抽屉的柜子,每个抽屉都有自己的ID(比如位置)来识别每个抽屉的位置,而根据ID我们打开相应的抽屉时就能够有对应的空间让我们放东西。
和这个柜子的特点一样, 数组有以下特点:

  1. 固定长度(柜子的大小和抽屉的个数是固定的)
  2. 类型相同(这个柜子只能放一类的物品)
  3. 可以通ID寻址(比如按照柜子的抽屉的高度顺序来标号)

1.2 数组的底层内存构成 (Memory of Array)

在Java里面假设我有一个array名字叫做a, 我们可以把它看成是一个柜子的名字a, 然后我这个柜子里面存放的是叫做 int整型的数据(物品), 那么我这个这个柜子有5个抽屉,那么在创建数组时就是写成int a[] = new int[5]。 而这个时候这个array的名字地址a就放到stack栈里面,相对于把这个柜子的名字放到一个列表,方便知道柜子在什么地方。而柜子的内容放到一个叫heap堆的空间里面。当我们要用时就先找a的地址,然后再再找第i个抽屉,把数据拿出来。即 读取a[i]的数据。

上面提及的存放array的名字和数据的内存有以下:

  • Stack 栈内存:栈内存存储的都是局部变量,变量一旦出了自己的作用域,那么就会马上从内存的消失,释放内存空间。

  • Heap 堆内存:堆内存存储的都是对象内存,对象一旦被使用完,并不会马上从内存中消失,而是等待垃圾回收器不定时的把垃圾对象回收,这时候该对象才会消失,释放内存。

  • 凡是以new关键字创建的对象,JVM都会在堆内存中开辟一个新的空间,创建一个新的对象。 对象如果没有变量引用了,那么该对象就是一个垃圾对象了。

2. 数组基本操作Array Operations

2.1 数组创建Creation

  • 数组申明 declaration
    当我们想要告诉程序,我们要定义一个数组,但还没有初始化赋予空间时,我们可以简单通过下面语句declare。 第一种是Java的常见写法,第二种是C++的写法。但是这样做,数组还没有开储存空间,所以不能直接用,这样就涉及到数组的初始化。
    1
    2
    3
    4
    int [] arr;
    //or

    int arr[];
  • 数组初始化 Initialization
    在Java里面初始化数组一般要new关键词, 除非是定义数组同时直接赋值。
    在数组的初始化我们可以用下面方法定义数组并赋值:
  1. 先定义后赋值
    1
    2
    3
    4
    5
    int [] a;
    a = new int[5];
    a[0] = 1;
    a[1] = 2;
    ...
    或者
    1
    2
    int [] a;
    a = new int[5]{1,2,3,4,5};
  2. 定义的同时赋值
    1
    int [] a = {1,2,3,4,5}

2.2 数组遍历Iteration

  • 方法1: 用index遍历数组
    在Java的数组里, 数组的index都是从0开始的,所以如果有n个元素在数组,那么就最大的index = n-1. 比如以下代码里面对a数组打印是从0打印到4, a数组的大小为5.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Demo{

    public static void main(){
    int [] a = {1,2,3,4,5};
    for(int i=0; i< a.length; i++){
    System.out.println(a[i]);
    }
    }
    }
  • 方法2: 用for each 遍历数组
    另外一种数组的遍历是用for each来遍历有点类似python里面的for x in ls:的用法,以及C++里面的for(auto x : ls)的用法。 for each的方法要比index遍历的方法简洁,但是不能拿到index,只能直接拿数据item。

    1
    2
    3
    4
    5
    6
    7
    8
    public class Main {
    public static void main(String[] args) {
    int[] ns = { 1, 4, 9, 16, 25 };
    for (int n : ns) {
    System.out.println(n);
    }
    }
    }

2.3 数组的常用的API

  • Arrays.sort()
    排序是数据结构算法的很基础的一个操作,因此Array的类也有对应的API. 这里我们先调用这个API,再尝试自己写一个。
    这里我们先通过java.util.Arrays调用Array 类然后再调用这个类里面的Array.sort()的方法。 Note: Array.sort()的方法的输入可以是不同的类,如int, float, double, String 等,如果是String会按照第一个字母的ASCII码进行排序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import java.util.Arrays;

    public class Main {
    public static void main(String[] args) {
    int[] ns = { 12,0,-4,-9, 20, 30, -100};
    Arrays.sort(ns);
    System.out.println(Arrays.toString(ns));
    }
    }

    这里实现一个insertion sort

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // 降序排序
    import java.util.Arrays;

    public class Main {
    public static void main(String[] args) {
    int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
    // 排序前:
    System.out.println(Arrays.toString(ns));
    // TODO: insertion sort
    int tmp;
    for(int i=0; i< ns.length-1;i++){
    tmp = ns[i];
    //find max
    for(int j= i+1; j< ns.length;j++ ){
    if(ns[j]> tmp){
    tmp = ns[j];
    ns[j] = ns[i];
    ns[i] = tmp;
    }
    }

    }
    // 排序后:
    System.out.println(Arrays.toString(ns));
    if (Arrays.toString(ns).equals("[96, 89, 73, 65, 50, 36, 28, 18, 12, 8]")) {
    System.out.println("测试成功");
    } else {
    System.out.println("测试失败");
    }
    }
    }
  • Arrays.toString()
    Array的toString函数可以把一个array(包括中括号[]) 转成一个String, 比如把[96, 89, 73, 65, 50, 36, 28, 18, 12, 8] 转成 “[96, 89, 73, 65, 50, 36, 28, 18, 12, 8]”。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class Main {
    public static void main(String[] args) {
    int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
    // 排序前:
    System.out.println(Arrays.toString(ns));

    System.out.println(Arrays.toString(ns));
    if (Arrays.toString(ns).equals("[28, 12, 89, 73, 65, 18, 96, 50, 8, 36]")) {
    System.out.println("测试成功");
    } else {
    System.out.println("测试失败");
    }
    }
    }
  • Arrays.fill()
    数组中的元素定义完成后,可通过Arrays类的静态方法fill()方法来对数组中的元素进行分配,起到填充和替换的效果。fill()方法可将指定的int值分配给int型数组的每个元素。用法∶Arrays.fill(int[] a ,int value)

2.4 更高维度的数组Higher dimensional array

2.4.1 2D array

2D array的创建和1D的差不多,一样用new关键词进行创建。不过2D array里面每一行的长度可以不一样。array[row][col] 2D array的第一个index代表row的index,第二个index是column的index.

以上面图为例, array是一个存放了每个row的起始的地址的列表,而 array[i] 地址指向了第i个row的数组。而2D array的每个element都是放到Heap里面的

1
2
3
4
int[][] a = {{1}, {1,2}, {1,2,3}};
//or

int[][] a= new int[][] {{1}, {1,2}, {1,2,3}};
1
2
3
4
5
6
7
8
9
10
public class Main {
public static void main(String[] args) {
int[][] ns = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
System.out.println(ns.length); // 3
}
}

在上面这个数组里面,它的结构是

1
2
3
4
5
6
7
8
9
10
                ns[0][1].........ns[0][3]
┌───┬───┬───┬───┐
┌─────┐ ┌──>│ 1 │ 2 │ 3 │ 4 │
ns ─────>│ns[0]│──┘ └───┴───┴───┴───┘
├─────┤ ┌───┬───┬───┬───┐
│ns[1]│─────>│ 5 │ 6 │ 7 │ 8 │
├─────┤ └───┴───┴───┴───┘
│ns[2]│──┐ ┌───┬───┬───┬───┐
└─────┘ └──>│ 9 │10 │11 │12 │
└───┴───┴───┴───┘

3. Coding Practice

这里我自己写一个2D binary Search 的leetcode的题目来练习一下2D array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.util.Arrays;

public class Task3{

public static void main(String[] args){

//2D array
int[][] arr = new int[][]{
{1,2,3,4,5},
{3,5,7,8,10},
{6, 9, 11, 16, 21},
{9, 11, 14, 18, 25},
{15, 16, 19, 40, 50}
};
System.out.println("Array: ");
for(int i=0; i< arr.length;i++){
System.out.println(Arrays.toString(arr[i]));
}
//binary search in 2D ascending array
int r = 0, c = arr[0].length-1;
int target = 18;
System.out.println("Target: "+ target);
while(r < arr.length && c >=0){
if(arr[r][c] < target){ r += 1; }
else if(arr[r][c]>target){c -= 1;}
else{
System.out.printf("Position: row: %d, col: %d\n", r,c);
break;


}
}
if(r>= arr.length && c<0) {System.out.println("Target not found");}

}

}

Compile Commands:

1
2
$ javac Task3.java
$ java Task3

Output:

1
2
3
4
5
6
7
8
Array:
[1, 2, 3, 4, 5]
[3, 5, 7, 8, 10]
[6, 9, 11, 16, 21]
[9, 11, 14, 18, 25]
[15, 16, 19, 40, 50]
Target: 18
Position: row: 3, col: 3

4. Comparison between C++ Array and Java Array

Properties C++ Array Java Array
Type NOT Object/Class Java Array is a Class
Declaration int arr[size]=
{…}
int[] arr =
new int[size]
//usually use “new”
Initialization int arr[size] int[] arr
check size of array sizeof() array.length

5. Reference

[1] https://stackoverflow.com/questions/17185906/what-is-the-difference-between-int-arr1-null-and-int-arr1-int-5-re

[2] Java Tutorial: https://www.liaoxuefeng.com/wiki/1252599548343744/1259544232593792
[3] Datawhale: https://github.com/datawhalechina/team-learning-program/blob/master/Java/4.%E6%95%B0%E7%BB%84.md

Comments