数组

  • 1 数组的基本概念
  • 1.1 数组的定义
  • 1.2 数组的创建
  • 1.3 数组的使用
  • 1.3.1 获取数组元素
  • 1.3.2 获取数组长度
  • 1.3.3 数组的遍历
  • 2 数组作为方法的参数
  • 2.1 基本用法
  • 3 数组练习
  • 3.1 数组转字符串
  • 3.2 数组拷贝
  • 3.3 找数组中的最大元素
  • 3.4 求平均值
  • 3.5 查找数组中的指定元素
  • 3.6 查找数组中指定元素(二分查找)
  • 3.7 检查数组的有序性
  • 3.8 冒泡排序
  • 3.9 数组逆序
  • 3.10 数组数字排列


1 数组的基本概念

1.1 数组的定义

  数组,本质上就是,批量的创建一组相同类型的变量。
  如果代码比较简单,只需要int a、int b两个数据就可以了,如果代码十分复杂需要创建一千个变量,我们可不能一个一个的 int 创建出来,这时候就需要 “ 规模制造 ”,用数组批量的一下子创建出来。注意,批量制造的一定得是***相同类型***。

1.2 数组的创建

三种数组的创建方式:

//1)数组的元素通过{}来指定
int[] arr1 = new int[]{1,2,3,4};
//2)数组的元素通过{}来指定
int[] arr2 = {1,2,3,4};         //一般写这样
//3)此时数组中的每个元素都被初始化成了0
//   这种写法主要用于指定长度
int[] arr3 = new int[4];

  我们会发现,在C语言中,数组是int arr[4]={1,2,3,4}; 这样写的。在Java中,int 和 [ ] 写在一起,它们原则上来说,应该是一个整体,共同构成了变量的类型。
  在C语言中,int[4] 和int[5] 是两种不同的类型,也就不能相互赋值,但是在Java中就没有这个问题,不管数组长度如何,是一个类型,就可以相 互赋值。
注意 一种错误写法:
中括号中数和大括号不能同时存在,以此避免数和大括号中的个数不相同。

int arr4 = new int[4]{1,2,3,4};     //编译出错

1.3 数组的使用

1.3.1 获取数组元素

和C语言类似,也是通过下标的方式来获取元素,不要忘记,大部分语言下标都是从 0 来时计算的,最后一个元素下标为length-1。使用下标访问的时候,不能超出有效范围,如果超出有效范围,在Java中会抛出一个数组下标越界异常

1.3.2 获取数组长度

数组一旦创建好了之后,长度(length)就固定了,无法动态进行修改。通过arr1.length 来获取数组的长度。

System.out.println(arr1.length);

注意:

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

1.3.3 数组的遍历

第一种方法:

int[] arr = {1,2,3,4};
for (int i = 0; i < arr.length ; i++) {
    System.out.println(arr[i]);
}

第二种方法,foreach方法,更简洁,但注意不能通过x 对数组进行修改:

for (int x : arr){
    System.out.println(x);
}

2 数组作为方法的参数

2.1 基本用法

(1) 数组赋值:

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

java 参数为数组类型 java 数组传参_java 参数为数组类型


(2) 数组传参:

  数组传参相当于 “ 赋值 ” 。赋值的时候,不是把原来的数组拷贝了一份形成新的数组,而是给原来的数组又起了个别名。数组是引用类型之一。

区分:内置类型在进行 = 的时候,不是起别名,而是创建了一个新的变量。

int[] arr = {1,2,3,4};
printArray(arr);
public static void printArray(int[] arr) {
    for (int i = 0; i <arr.length ; i++) {
        System.out.println(arr[i]);
    }

通过别名修改数组,再从别的名字 “ 看 ” 都能看到

int[] arr = {1,2,3,4};
int[] a = arr;
transform(a);
printArray(arr);
public static void printArray(int[] arr) {
    for (int i = 0; i <arr.length ; i++) {
        System.out.println(arr[i]);
    }
}
public static void transform(int[] a){
    a[0] = 100;
}

(3) 写一个方法,把数组中的每个元素都 * 2

public static int[] transform2(int[] a){
    for (int i = 0; i <a.length ; i++) {
        a[i] = a[i] * 2;
    }
    return a;
}

  这样写,输出的结果就是乘二的数组,但是因为对a 直接进行操作,也就是通过别名对数组本体进行了操作改变,就无法保留原数组了。怎么样保留原数组呢,我们可以再创建一个数组。
  为了保留了原来的数组,new 了一个新的数组,然后对新数组进行乘二的操作,再返回这个新数组,就可以既保留原数组又得到一个乘二的新数组。

public static int[] transform2(int[] a){
    int[] result = new int[a.length];
    for (int i = 0; i <a.length ; i++) {
        result[i] = a[i] * 2;
    }
    return result;
}

  要注意,这个逻辑在C语言中是会出现问题的,在C 中result 在函数执行完之后会被释放,result 会变成野指针,再对它进行操作就有问题了,但是,在Java 中可以。这是因为它们的生命周期不一样,即变量 ” 什么时候生成 什么时候释放 “ 的问题。在Java 中new 出来的对象的生命周期,是根据垃圾回收器自动判定的。

3 数组练习

3.1 数组转字符串

需求:查看数组的内容,希望可以更方便的观察,就可以把数组的内容按照一定的格式组织成一个字符串。
(1)我们可以写一个方法,将数组转换成String ,注意这中间的加号 “ + “ 是String字符串和数字,因此它执行的是字符串的拼接而不是数字相加的运算。

public static String arrayToString(int[] arr){
    String result = "[";
    for (int i = 0; i < arr.length; i++) {
        result += arr[i];
        if(i != arr.length-1){
            result +=",";
        }
    }
    result += "]";
    return result;
}

(2) 标准库中其实有这样的方法我们可以直接使用,在Arrays中有这种方法,而且它重载了很多种类型。

java 参数为数组类型 java 数组传参_i++_02

3.2 数组拷贝

(1) 我们可以写一个方法进行拷贝

public static int[] copyOf(int[] arr) {
    int[] result = new int[arr.length];
    for (int i = 0; i <arr.length ; i++) {
        result[i] = arr[i];
    }
    return result;
}

(2) 同样也可以用标准库中的方法进行拷贝,我们可以看到,标准库的拷贝有两个参数,一个是数组名,一个是长度,如果新数组比原数组长度短,则相当于截断;如果新数组比原数组长度长,则长出来的部分自动用0 填充。

int[] result = Arrays.copyOf(arr,arr.length);

//拷贝某一部分
int[] result = Arrays.copyOfRange(arr, 2, 4);
System.out.println("result: " + Arrays.toString(result));

3.3 找数组中的最大元素

  通过将一个位置固定当作 ” 擂台 “,然后其他的数来 ” 打擂台 “ 的方式进行比较,就是先固定一个位置,然后遍历其他的数与之比较大小,比它大就上去替代它,别的数再来比较,比擂台上的大就将擂台上的数 ” 打下擂台 “,大的数再站在擂台上,留到最后的就是最大的数。

public static int max(int[] arr) {
    int result = arr[0];
    for (int i = 0; i <arr.length ; i++) {
        if(arr[i] > result){
            result = arr[i];
            arr[i] = result;
        }
    }
    return result;
}

3.4 求平均值

  即,将数组中的数全部加起来,然后处以数组的长度,来求得平均值,要注意平均值最后的返回值应该用double 类型,因为它不一定是整数。

public static double avg(int[] arr) {
    int sum = 0;
    for (int i = 0; i <arr.length ; i++) {
        sum += i;
    }
    return  (double) sum/ arr.length;
}

3.5 查找数组中的指定元素

  给定值,查找下标,就是找到指定元素的位置。

public static int search(int[] arr, int toSearch) {
    int index = 0;
    for (index = 0; index <arr.length ; index++) {
        if(toSearch == arr[index]){
            return index;
        }
    }
    System.out.println("找不到该数。");
    return -1;
}

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

  针对有序数组, 可以使用更高效的二分查找,即,先找到这组有序数组的中间值,然后比较要找的元素和中间值,如果比中间值小,则把中间后面的 ” 砍掉 “,再在前半段找中间值,判断要找元素与中间值的大小,重复上述操作直至找到制定元素;如果比中间值大,则把中间值前面的 ” 砍掉 “,在前半段找中间值,判断要找元素与中间值的大小,重复上述操作直至找到制定元素。

public static int binarySearch(int[] a, int toSearch) {
    int left = 0;
    int right = a.length-1;
    while (left <= right ) {
        int mid = left + right / 2;
        if( toSearch > a[mid] ){
        //在后半段查找
            left = mid + 1;
        }else if( toSearch < a[mid]){
        //在左半段查找
            right = mid -1;
        }else{
        // to
            return mid;
        }
    }
    System.out.println("找不到该数。");
    return -1;
}

3.7 检查数组的有序性

找反例:
  依次循环来找数组中的相邻元素,看相邻的两个元素是否符合升序要求,只要找到一个不符合的,反例就出来了,就可以认为不是有序数组;如果找完了所有的相邻元素,都没有找到反例,就是有序。

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;
}

3.8 冒泡排序

public static void bubbleSort(int[] arr) {
    //从后往前遍历
    //外层循环遍历的次数
    //已排区间[0,bound)
    //待排区间[bound,length)
    for (int bound = 0; bound <arr.length ; bound++) {
    //里层循环,比较交换
        for (int cur = arr.length-1; cur >0 ; cur--) {
            if(arr[cur - 1] > arr[cur]){
                //不符合排序要求
                int tmp = 0;
                tmp = arr[cur - 1];
                arr[cur - 1] = arr[cur];
                arr[cur] = tmp;
            }
        }
    }
}

3.9 数组逆序

  逆序是要修改数组的内容,而不是反向打印(不修改内容)

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 --;
    }
}

3.10 数组数字排列

  从左往右,找到一个奇数;再从右往左,找到一个偶数;把这两个数交换,直到两个下标重合。

public static void transform2(int[] arr) {
    int left = 0;
    int right = arr.length-1;
    while(left<right){
        //先从左往右找到一个奇数
        while(left<right && arr[left] % 2 ==0){
            left++;
        }
        //从右往左找到一个偶数
        while(left<right && arr[right] % 2 !=0){
            right--;
        }
        //交换left和right
        int tmp =arr[left];
        arr[left] = arr[right];
        arr[right] = tmp;
    }
}