2016-06-16 71 views
0

我已經編寫了用於在scala中搜索整數數組的二進制代碼,如下所示。我知道二分查找實施起來相當棘手。所以,我想知道這個代碼是否總能正常工作。我已經通過對測試數組進行測試來嘗試它,並且它可以工作。但是,我不確定它是否會始終有效。我的二進制搜索實現能夠正常工作嗎?

NOTE:假設數組大小永遠不會超過最大整數值的一半。

def binarySearch(arr: Array[Int], starti: Int, endi: Int, x: Int) : Int = 
{ 
    if (starti > endi) 
     return -1 

    val guess = (starti + endi)/2 

    if (arr(guess) == x) 
     return guess 

    if ((guess != 0) && (arr(guess-1) == x)) 
     return guess - 1 

    if ((guess != endi) && (arr(guess+1) == x)) 
     return guess + 1 

    if (arr(guess) > x) 
     return binarySearch(arr, starti, guess-1, x) 
    else 
     return binarySearch(arr, guess+1, endi, x) 
} 
+3

它包含經典的中點計算溢出添加,它可以變爲負值,除以2會使其負值(邏輯移位可以正常工作),然後您的負指數。 – harold

+0

正數如何除以2產生負數?假設數組大小不超過最大整數值。 – pythonic

+0

由2除以不產生負數,加法確實。該部門只是將其保留爲負值,而通過將添加的結果視爲未簽名來處理該部分。 – harold

回答

2

在你的假設它似乎是正確的。不過,我總是建議編寫val guess = starti + (endi - starti)/2而不是val guess = (starti + endi)/2,因爲後者在一般情況下可能會溢出(但不是在您的假設下)。

此外,搜索鄰居是相當罕見的,在你的情況下,它只是開銷,因爲您使用return binarySearch(arr, starti, guess-1, x)代替return binarySearch(arr, starti, guess-2, x),類似的還有return binarySearch(arr, guess+1, endi, x),忽略你已經檢查了這些。

我建議刪除guess的鄰居測試。相反,計算間隔的大小(endi - starti),如果它小於某個閾值,則線性搜索數組x(由於緩存的工作原理,線性遍歷速度相當快)。如果它更大,則使用遞歸二進制搜索。請注意,在下面的示例中,我稍微更改了界面:給定搜索間隔不包括endi以使初始呼叫更加舒適(binarySearch(arr, 0, arr.length, x))。

def binarySearch(arr: Array[Int], starti: Int, endi: Int, x: Int) : Int = 
{ 
    val threshold = 100 

    val len = endi - starti 
    if (len <= 0) { 
     return -1 
    } 

    // Optional and purely for performance reasons 
    if (len < threshold) { 
     for (i <- starti until endi) { 
      if (arr(i) == x) { 
       return i 
      } 
     } 
    } 


    val guess = starti + len/2 
    if (arr(guess) == x) { 
     return guess 
    } else if (arr(guess) > x) { 
     return binarySearch(arr, starti, guess, x) 
    } else { 
     return binarySearch(arr, guess + 1, endi, x) 
    } 
} 

請注意,閾值只是隨機猜測,必須通過性能測量來確定。

+0

我添加了返回-1的情況,當找不到x時。請參閱函數中的第一行。另外,我的假設是數組大小永遠不會超過整數最大值的一半。 – pythonic

+0

@ hk6279。你在問我的代碼嗎?如果是這樣,它會搜索它,也就是說,它會返回0. – pythonic

+1

它將返回0,因爲這是第一個索引(剛剛測試過)。請注意,我的版本的界面與原版界面略有不同。在原始版本中,包含'endi'的區間在我的版本中被排除。恕我直言,這使得初始調用更優雅,因爲你可以使用'binarySearch(arr,0,arr.length,x)',但只是個人偏好。 – Nicolas