【Java】08 Array 数组

概述

数组是多个相同数据类型按一定顺序排列的一组数据

特点:

- 数据类型相同!!

- 长度固定!!

构成数组的几个要素

- 数组名称

- 下标,又称索引  

- 元素

- 数组长度

 

数组是一种引用类型,就像使用变量一样必须要有引用才能可控的访问

下标是数组的书签,访问数组的元素必须依靠下标

元素,数组所存储的数据,元素的数据类型必须和数组相同

长度,数组所存储的元素的个数

按维度分类,可以分为一维数组和多维数组

声明与初始化

 

package cn.dai;

public class Arrays {
    public static void main(String[] args) {
        
        //声明一个数组
        int[] array;
        
        // 初始化
        array = new int[]{1,2,3,4,5,6,7};
        
        // 如果简写,也就是静态初始化,必须 声明和初始化同时完成
        int[] array2 = {2,3,4,5,7,8,9};
        
        // 或者不对数组具体赋值元素而是初始化时声明数组的长度
        int[] array3 = new int[10];
    }
}

 

 

访问元素和使用下标

package cn.dai;

public class Arrays {
    public static void main(String[] args) {
        int[] array = {1,3,5,7,9};
        
        // 下标起始位置从0开始,结尾到数组的长度-1
        System.out.println(array[0]);
        
        // 通过下标更改元素的值
        array[3] = 10;
    }
}

 

长度与遍历

package cn.dai;

public class Arrays {
    public static void main(String[] args) {
        int[] array = {1,3,5,7,9};
        
        // 使用for循环遍历数组 length是数组的一个属性,表示数组的长度
        for (int i = 0; i < array.length ; i++) {
            System.out.println( array[i] );
        }
    }
}

 

默认值?引用类型的属性问题

 

一维数组的内存分布图

 

 

 

 

多维数组

 

声明和初始化

package cn.dai;

public class Arrays {
    public static void main(String[] args) {
        
        // 二维数组的初始化 静态
        int[][] array = new int[][]{
                {1,3,5,7,9},
                {2,4,6,8,10}
        };
        
        // 动态 二维数组可以只声明外围长度,
        // 内围数组没有声明就是未初始化的状态
        // Java允许内围可以先不初始化
        int[][] array2 = new int[4][];
    }
}

 

下标访问和遍历

package cn.dai;

public class Arrays {
    public static void main(String[] args) {

        // 二维数组的初始化 静态
        int[][] array = new int[][]{
                {1,3,5,7,9},
                {2,4,6,8,10}
        };

        // 元素的访问 
        System.out.println(array[1][2]);
        
        // 遍历
        
        // 先遍历外围长度,也就是内围的数组个数
        for (int i = 0; i < array.length; i++) {
            
            // 再遍历下标指向的数组
            for (int j = 0; j < array[i].length ; j++) {
                
                // 这样就能遍历每一个元素了
                System.out.println( array[i][j] );
            }
        }
    }
}

 

数组练习

杨辉三角/帕斯卡三角

package cn.dai;

public class Arrays {
    public static void main(String[] args) {

        // 杨辉三角形  外围的长度不限制 (不要低于5)
        int[][] pascalTriangle = new int[10][];

        // 名字太长 声明一个简写引用一下
        int[][] tri = pascalTriangle;

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

            // 声明内围的数组
            tri[i] = new int[i + 1];
            // 连续赋值 每一行,也就是每一组数组的头和尾都是1
            tri[i][0] = tri[i][i] = 1;

            // 对既不是头也不是尾的内部元素进行赋值
            for (int j = 1; j < tri[i].length - 1 ; j++) {
                tri[i][j] = tri[i - 1][j - 1] + tri[i - 1][j];
            }
        }

        // 打印查看
        for (int i = 0; i < tri.length; i++) {
            for (int j = 0; j < tri[i].length; j++) {
                System.out.print(tri[i][j]+"\t");
            }
            System.out.println();
        }
    }
}

 

一维数组:求最大最小值,平均值,总和

package cn.dai;

public class Arrays {

    // 求最大值
    static int getMaximum(int[] array){
        // 设置游标
        int max = array[0];
        // 因为已经设置第一个赋值给了游标 从第二个开始遍历
        for (int i = 1; i < array.length; i++) {
            // max = array[i] > max ? array[i] : max;
            max = Math.max(array[i], max);
        }
        return max;
    }

    // 求最小值
    static int getMinimum(int[] array){
        int min = array[0];
        for (int i = 1; i < array.length; i++) {
            // min = array[i] < min ? array[i] : min;
            min = Math.min(array[i], min);
        }
        return min;
    }

    // 求和
    static int getSummation(int[] array){
        int sum = 0;
        for (int element : array) {
            sum += element;
        }
        return sum;
    }
    
    // 求平均值
    static double getAverage(int[] array){
        double sum = 0.0;
        for (int element : array) {
            sum += element;
        }
        return sum / array.length;
    }
}

 

一维数组的复制

package cn.dai;

public class Arrays {
    public static void main(String[] args) {
        
        int[] array = {1,3,5,7,9};
        
        // 先复制长度
        int[] array2 = new int[array.length];

        for (int i = 0; i < array2.length; i++) {
            // 复制元素
            array2[i] = array[i];
        }
    }
}

 

一维数组的反转

package cn.dai;

public class Arrays {
    public static void main(String[] args) {
        int[] array = {1,2,5,10,9};
    }
    
    static int[] reverse1(int[] array){
        // 遍历一半长度进行元素交换
        for (int i = 0; i < array.length / 2; i++) {
            int temp = array[i];
            array[i] = array[array.length - 1 - i];
            array[array.length - 1 - i] = temp;
        }
        return array;
    }

    static int[] reverse2(int[] array){
        // 头尾双向交换 
        for ( int i = 0,j = array.length -1; i < j ; i++,j--) {
            int temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
        return array;
    }
}

 

一维数组的线性查找 和 二分查找

package cn.dai;

public class Arrays {
    public static void main(String[] args) {
        int[] array = {1,2,5,10,9};
    }

    // 线性查找
    static int linearSearch(int[] array,int target){
        for (int i = 0; i < array.length; i++) {
            if (target == array[i]) return i;   // 找到直接返回索引
        }
        return -1; // 找不到 返回-1
    }

    // 二分查找
    static int binarySearch(int[] array,int target){
        int start = 0;
        int end = array.length -1;
        
        while ( start <= end ){
            int mid = (start + end) / 2; // 每次二分都在不断变化的中轴游标
            if (target == array[mid]) return mid; // 碰上了正好直接返回
            else if (target > array[mid]) start = mid + 1; // 目标位置大于中轴,起始位置前推 
            else end = mid + 1; // 反之后退
        }
        return -1;
    }
}

 

【排序算法】

衡量排序算法的指标

- 时间复杂度  需要比较的次数和记录的移动次数

- 空间复杂度  内存耗费

- 稳定性  是否需要改变数据

按内外状态划分

- 内部排序 不需要外界辅助实现算法

- 外部排序 算法需要多部份完成,依赖外界辅助实现

 

【算法的特征】

- 对输入的描述和定义必须正确

- 输出必须要有结果产生

- 有穷性,在完成计算实现之后必须停止

- 确定性,算法的每一步都是明确的,不会歧义

- 可行性,算法的每一步都是清晰的,纸笔也能实现答案获取

 

冒泡排序

package cn.dai;

public class Arrays {
    public static void main(String[] args) {
        int[] array = {1,2,5,10,9};
    }

    // 冒泡排序
    static int[] bubbleSort(int[] array){
        
        for (int i = 0; i < array.length -1; i++) {

            for (int j = 0; j < array.length -1; j++) {
                
                if (array[j] > array[j + i]){
                    int temp = array[i];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
            
        }
        return array;
    }
}

 

快速排序 递归

 https://blog.csdn.net/shujuelin/article/details/82423852

package cn.dai;

public class Arrays {
    public static void main(String[] args) {
        int[] array = {1,2,5,10,9};
    }
    
    // 快速排序
    static void quickSort(int[] arr,int start,int end){
        int i,j,temp,t;
        if(start > end) return;
        i = start;
        j = end;
        //temp就是基准位
        temp = arr[start];

        while (i < j) {
            //先看右边,依次往左递减
            while (temp <= arr[j] && i<j) j--;
            
            //再看左边,依次往右递增
            while (temp>=arr[i]&&i<j) i++;
            
            //如果满足条件则交换
            if (i<j) {
                t = arr[j];
                arr[j] = arr[i];
                arr[i] = t;
            }

        }
        //最后将基准为与i和j相等位置的数字交换
        arr[start] = arr[i];
        arr[i] = temp;
        //递归调用左半数组
        quickSort(arr, start, j-1);
        //递归调用右半数组
        quickSort(arr, j+1, end);
    }
}

 

Arrays工具类

直接看源码,这里有非常多的重载

右边可以看到所有基本类型的重载方法

Arrays.sort() 将参数数组按顺序方式排序

 

关于parallelSort并行排序的资料:

https://www.infoq.cn/article/Java-8-Quiet-Features/

 

二分的重载

 

判断两个数组是否相同

fill 填充数组 你可以设置填充范围,不过默认全填充

 

复制数组直接照搬系统的复制方法...

 

将数组转换成String字符串形式

 

越界异常

package cn.dai;

public class Arrays {
    public static void main(String[] args) {
        int[] array = {1,2,5,10,9};

        // 越界异常 访问超过索引个数的位置
        System.out.println(array[11]);
    }
}
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 11
    at cn.dai.Arrays.main(Arrays.java:10)

Process finished with exit code 1

 

数组比较,判断是否相等

比较的依据分两种,判断地址是否一致,按存储的元素和顺序是否一致:

        int[] arrayA = {1, 3, 5};
        int[] arrayB = arrayA;
        int[] arrayC = {1, 3, 5};

        System.out.println("arrayA == arrayC : " + (arrayA == arrayC));
        System.out.println("arrayA == arrayB : " + (arrayA == arrayB));
        System.out.println("arrayA.equals(arrayB) : " + (arrayA.equals(arrayB)));
        System.out.println("arrayA.equals(arrayC) : " + (arrayA.equals(arrayC)));

        System.out.println("Arrays.equals(arrayA, arrayB) : " + Arrays.equals(arrayA, arrayB));
        System.out.println("Arrays.equals(arrayA, arrayC) : " + Arrays.equals(arrayA, arrayC));

        // 存在多维数组的情况
        int[][] arrayD = {
            {1, 3}, {3, 4}, {5, 6}
        };
        int[][] arrayE = {
            {1, 3}, {3, 4}, {5, 6}
        };
        System.out.println("arrayD == arrayE : " + (arrayD == arrayE));
        System.out.println("Arrays.equals(arrayD, arrayE) : " + Arrays.equals(arrayD, arrayE));
        System.out.println("Arrays.deepEquals(arrayD, arrayE) : " + Arrays.deepEquals(arrayD, arrayE));

        System.out.println("Arrays.deepEquals(null, null) : " + Arrays.deepEquals(null, null));

查看打印结果:

arrayA == arrayC : false
arrayA == arrayB : true
arrayA.equals(arrayB) : true
arrayA.equals(arrayC) : false
Arrays.equals(arrayA, arrayB) : true
Arrays.equals(arrayA, arrayC) : true
arrayD == arrayE : false
Arrays.equals(arrayD, arrayE) : false
Arrays.deepEquals(arrayD, arrayE) : true
Arrays.deepEquals(null, null) : true

Process finished with exit code 0

  

我们知道 双等号是取引用存放的地址进行比较

但是发现数组对象自带的equals方法也返回false

查看方法所属的类是Object,可以得知数组的equals方法是没有重写处理的

就是按照Object类默认的方式进行比较:

    public boolean equals(Object obj) {
        return (this == obj);
    }

所以下面两种办法是等同的:

arrayA == arrayC : false
arrayA.equals(arrayC) : false

再来看Arrays工具类提供的比较办法:

1、优先看地址,一样的就不用看其它条件,直接确认一致

2、如果其中一个为空就返回false

3、看长度是否一致,长度都不一样就确认不是了

4、然后遍历元素,取元素来比较是否一直

    public static boolean equals(int[] a, int[] a2) {
        if (a==a2)
            return true;
        if (a==null || a2==null)
            return false;

        int length = a.length;
        if (a2.length != length)
            return false;

        for (int i=0; i<length; i++)
            if (a[i] != a2[i])
                return false;

        return true;
    }

  

多维数组的比较使用的是Arrays工具类的deepEquals()方法

    public static boolean deepEquals(Object[] a1, Object[] a2) {
        if (a1 == a2)
            return true;
        if (a1 == null || a2==null)
            return false;
        int length = a1.length;
        if (a2.length != length)
            return false;

        for (int i = 0; i < length; i++) {
            Object e1 = a1[i];
            Object e2 = a2[i];

            if (e1 == e2)
                continue;
            if (e1 == null)
                return false;

            // Figure out whether the two elements are equal
            boolean eq = deepEquals0(e1, e2);

            if (!eq)
                return false;
        }
        return true;
    }

该方法要求入参对象是Object数组类型,可以尝试把一维基本类型数组放进去之后会编译报错

因为一维数组的对象定义为Object类型,所以类型是不匹配的

判断思路还是一致,常规的地址,空指针,长度不一致是先判断

 

在元素比较时单独封装了一个方法来编写

1、如果元素还是一个数组对象,会递归调用深度比较方法,也就是多维数组会被方法依次剥离引用来判断

2、直到剥离成最基本的一维数组时,开始调用其他基本类型一维数组方法去处理,方法得到了复用

    static boolean deepEquals0(Object e1, Object e2) {
        assert e1 != null;
        boolean eq;
        if (e1 instanceof Object[] && e2 instanceof Object[])
            eq = deepEquals ((Object[]) e1, (Object[]) e2);
        else if (e1 instanceof byte[] && e2 instanceof byte[])
            eq = equals((byte[]) e1, (byte[]) e2);
        else if (e1 instanceof short[] && e2 instanceof short[])
            eq = equals((short[]) e1, (short[]) e2);
        else if (e1 instanceof int[] && e2 instanceof int[])
            eq = equals((int[]) e1, (int[]) e2);
        else if (e1 instanceof long[] && e2 instanceof long[])
            eq = equals((long[]) e1, (long[]) e2);
        else if (e1 instanceof char[] && e2 instanceof char[])
            eq = equals((char[]) e1, (char[]) e2);
        else if (e1 instanceof float[] && e2 instanceof float[])
            eq = equals((float[]) e1, (float[]) e2);
        else if (e1 instanceof double[] && e2 instanceof double[])
            eq = equals((double[]) e1, (double[]) e2);
        else if (e1 instanceof boolean[] && e2 instanceof boolean[])
            eq = equals((boolean[]) e1, (boolean[]) e2);
        else
            eq = e1.equals(e2);
        return eq;
    }

  

将数组转换成字符串的优雅方法:

int[][] arrayD = {
  {1, 3}, {3, 4}, {5, 6}
};
        
System.out.println("Arrays.toString(arrayD) -> " + Arrays.toString(arrayD));
System.out.println("Arrays.deepToString(arrayD) -> " + Arrays.deepToString(arrayD));

打印结果:

Arrays.toString(arrayD) -> [[I@7f31245a, [I@6d6f6e28, [I@135fbaa4]
Arrays.toString(arrayD) -> [[1, 3], [3, 4], [5, 6]]

分别适用在一维数组和多维数组中

 

posted @ 2020-04-16 03:03  emdzz  阅读(260)  评论(0编辑  收藏  举报