1. 程式人生 > 實用技巧 >Java:深入瞭解陣列Arrays.binarySearch方法的優缺點

Java:深入瞭解陣列Arrays.binarySearch方法的優缺點

目錄

背景

最近重新整理Java基礎知識,在練習陣列的過程中關於Arrays.binarySearch(type[] a,type key)方法的一系列問題以及解決方法

方法介紹

  Arrays.binarySearch(type[] a,type key),第一個輸入的值為相應資料型別的陣列,第二個為想要查詢的數值,如果查詢到這個數值就會返回該數值的下標,如果沒有找到,則返回插入值的負數。

PS:在使用Arrays.binarySearch(type[] a,type key)方法前,需要對陣列進行排序

例項

        int[] num=new int[]{5,8,3,10,1};
        //對陣列進行排序
        Arrays.sort(num);
        //排序後的陣列為[1,3,5,8,10]
        //查詢陣列num數值為8的下標,有結果,返回下標
        int num1=Arrays.binarySearch(num,8);
        //查詢陣列num數值為6的下標,無結果,返回-1或“-”(插入點)。插入點是索引鍵將要插入陣列的那一點,即第一個大於該鍵的元素的索引。
        int num2=Arrays.binarySearch(num,6
); int num3=Arrays.binarySearch(num,-6); //查詢數值num中下標為2到3中數值為8的下標 int num4=Arrays.binarySearch(num,2,3,8); //查詢數值num中下標為1到3中數值為3的下標 int num5=Arrays.binarySearch(num,1,3,3); System.out.println("查詢陣列num數值為8的下標,有結果"+num1); System.out.println("查詢陣列num數值為6的下標,無結果
"+num2); System.out.println("查詢陣列num數值為-6的下標,無結果"+num3); System.out.println("查詢數值num中下標為2到3中,數值為8的下標"+num4); System.out.println("查詢數值num中下標為2到3中,數值為3的下標"+num5);

結果

方法缺點:

到這一步這個方法一切都是如此簡單,我就不會寫這個部落格了,但是這個方法有1個無法解決的缺點,讓我們先看一下Java自己是如何介紹這個方法的。

對於英語不好的朋友我把第一段已經翻譯後,顯示在下面

使用二進位制搜尋演算法在指定的整數陣列中搜索指定的值。在進行此呼叫之前,必須對陣列進行排序(就像使用{@link#sort(int[])}方法一樣)。如果不排序,則結果未定義。
如果陣列包含多個具有指定值的元素,則無法保證將找到哪一個元素。

我加粗的那一行字,也就是說如果數值中有多個重複的值,它可能就無法正確定位到該位置。

例項

int[] num=new int[20];
        for (int i=0;i<num.length;i++){
            Random random=new Random();
            num[i]=random.nextInt(3)+1;
        }
        Arrays.sort(num);
        int num1=Arrays.binarySearch(num,1);
        int num2=Arrays.binarySearch(num,2);
        int num3=Arrays.binarySearch(num,3);
        System.out.println("1的下標"+num1);
        System.out.println("2的下標"+num2);
        System.out.println("3的下標"+num3);

結果

返回結果

實際結果

總結:所以當有多個相同的數值在陣列中,Arrays.binarySearch方法無法正確找到該數值的最後一個數值的索引,或者第一個數值的索引。

原因分析

原始碼檢視:檢視Arrays.binarySearch()方法,這裡以int型別作為解說

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

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

    // Like public version, but without range checks.
    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.
    }

我們可以看到呼叫Arrays.binarySearch()方法實際上就是呼叫binarySearch0()方法,binarySearch0()方法其實是一個二分查詢法,這就是為什麼我們使用Arrays.binarySearch()前需要進行排序,以及多個數值相同的數,無法精確定位下標的原因。

補充說明:

  當沒有定義int fromIndex, int toIndex時,fromIndex=0, toIndex=陣列長度

為什麼使用>>>(無符號位右移),而不是用>>(右移)這是避免資料過大,導致溢位

為什麼使用>>>位運算子,而不是直接除以2,這是因為>>>可以提高程式設計的執行速度