原來你是這樣的JAVA[04]-數組Arrays

一、打印數組

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章