原来你是这样的JAVA[04]-数组Arrays
阅读原文时间:2023年09月05日阅读:1

一、打印数组

Arrays类提供了打印数组元素的方法,Arrays.toString()和Arrays.deepToString()。

//打印数组
System.out.println(Arrays.toString(arr));//输出 [1, 3, 5, 7, 9]
//打印多维数组
int[][] arrM={{1,2,3},{11,12,13},{21,22,23}};
System.out.println(Arrays.deepToString(arrM));//[[1, 2, 3], [11, 12, 13], [21, 22, 23]]

Arrays.toString()源码实现:

public static String toString(int[] a) {
        if (a == null)
            return "null";
        int iMax = a.length - 1;
        if (iMax == -1)
            return "[]";

        StringBuilder b = new StringBuilder();
        b.append('[');
        for (int i = 0; ; i++) {
            b.append(a[i]);
            if (i == iMax)
                return b.append(']').toString();
            b.append(", ");
        }
    }

二、数组拷贝Arrays.copyOf

想拷贝数组元素到另外一个数组,需要使用Arrays.OfcopyOf(int[] original, int newLength) 方法,该方法第二个参数newLength表示新数组的长度。

  • 如果newLength小于原始数组长度,则只拷贝前面的元素;

  • 如果newLength大于原始数组长度,则多出来的长度会自动填充默认值。

     int[] arr={1,3,5,7,9};
       //拷贝数组元素
        int[] arr2=Arrays.copyOf(arr,arr.length);
        System.out.println(Arrays.toString(arr2));//输出   [1, 3, 5, 7, 9]
        int[] arr3=Arrays.copyOf(arr,arr.length/2);
        System.out.println(Arrays.toString(arr3));//输出 [1, 3]
        int[] arr4=Arrays.copyOf(arr,arr.length*2);
        System.out.println(Arrays.toString(arr4));//输出 [1, 3, 5, 7, 9, 0, 0, 0, 0, 0]

Arrays.copyOf方法针对各种数据类型做了重载,其中int[]类型源码如下:

    public static int[] copyOf(int[] original, int newLength) {
        int[] copy = new int[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

    @HotSpotIntrinsicCandidate
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

在JDK的Object类源码中,被@HotSpotIntrinsicCandidate标注的方法,在HotSpot中都有一套高效的实现,该高效实现基于CPU指令,运行时,HotSpot维护的高效实现会替代JDK的源码实现,从而获得更高的效率。

三、填充数组

Arrays.fill(int[] arr,int v)将数组arr的所有值都设置为数值v。

      String[] arr7 = new String[5];
        Arrays.fill(arr7, "*");
        System.out.println(Arrays.toString(arr7));//[*, *, *, *, *]

源码实现:

    public static void fill(Object[] a, Object val) {
        for (int i = 0, len = a.length; i < len; i++)
            a[i] = val;
    }

四、比较数组元素

Arrays.equals(type[]a,type[]b)如果两个数组大小相同,并且下标相同的元素都对应相等,返回true。

 //比较数组元素
String[] arr7 = {"*", "*", "*", "*", "*",};
String[] arr8 = {"*", "*", "*", "*", "*",};
System.out.println(arr7.equals(arr8));//false
System.out.println(Arrays.equals(arr7, arr8));//true

源码实现:

 public static boolean equals(Object[] a, Object[] 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 (!Objects.equals(a[i], a2[i]))
                return false;
        }

        return true;
    }

五、数组排序

1.数组排序原理

2.测试示例

        //排序
        int[] arr6 = {12, 4, 53, 78, 21, 943, 3};
        Arrays.sort(arr6);
        System.out.println(Arrays.toString(arr6));//输出 [3, 4, 12, 21, 53, 78, 943]

3.实现方式

说起排序先复习一下最常用的冒泡算法:冒泡排序的特点是,每一轮循环后,最大的一个数被交换到末尾,因此,下一轮循环就可以“刨除”最后的数,每一轮循环都比上一轮循环的结束位置靠前一位。

public void sort() {
        int[] arr = {28, 12, 89, 73, 65, 18, 96, 50, 8, 36};
        System.out.println(Arrays.toString(arr));
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int t = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = t;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }

接下来去看一下java中Arrays.sort的实现:

3.java数组排序算法:Dual-Pivot Quicksort

public static void sort(int[] a) {

DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);

}

dual-pivot quick sort是一种优化的双基快速排序。

首先回顾一下经典快速排序思路:

接受一个数组,挑一个数(pivot),然后把比它小的那一摊数放在它的左边,把比它大的那一摊数放在它的右边,然后再对这个数左右两摊数递归的执行快排过程,直到子数组只剩一个数为止。

双基快速排序思路:

在经典快排里面有一个pivot的概念,它是用来分隔大数和小数的,这个pivot把一个数组分成两份。那么所谓的Dual-Pivot其实就是用两个Pivot, 把整个数组分成三份。

双基快速排序快在哪里呢?首先看下衡量排序的标准:

元素比较次数:这是比较经典的衡量标准,可是由于CPU与内存的发展失衡,我们在分析算法复杂性的时候已经不能简单地用元素比较次数来比较了,因为这种比较的方法只考虑了CPU的因素,没有考虑内存的因素。

扫描元素个数:对于那种对输入数据进行顺序扫描的排序算法,扫描元素的个数这种新的算法把内存的流量的因素考虑进去,比较适应新时代。

从扫描元素个数准则来比较,双基快速排序要优于经典快速排序。

六、查找

static int binarySearch(type[]a,type v)。采用二分搜索算法查找值v。如果查找成功,则返回相应的下标值;否则,返回一个负数值r。-r-1是为保持a有序v应插入的位置。

        //输出2
        System.out.println(Arrays.binarySearch(arr6, 12));
        //输出7,及-(low+1)=7,所以如果该元素插入数组的位置应该是6
        System.out.println(Arrays.binarySearch(arr6, 100));

源码实现:

  public static int binarySearch(int[] a, int key) {
        return binarySearch0(a, 0, a.length, key);
    }

private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                     int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

七、数组引用

@Test
public void test() {
    String[] names = {"ABC", "XYZ", "zoo"};
    String s = names[1];
    names[1] = "cat";
    Assert.assertEquals("XYZ", s);
}

https://www.liaoxuefeng.com/wiki/1252599548343744/1255941599809248

https://www.jianshu.com/p/2c6f79e8ce6e

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器