[英]Why does this binary search implementation cause stack overflow in Ruby but not Java?
def binary_search(arr, l, r, x)
if r >= 1 then
mid = l + (r - 1) / 2
if arr[mid] == x then
return mid
end
if arr[mid] > x then
return binary_search(arr, l, mid - 1, x)
end
return binary_search(arr, mid + 1, r, x)
end
return -1
end
int binarySearch(int arr[], int l, int r, int x)
{
if (r >= l) {
int mid = l + (r - l) / 2;
// If the element is present at the
// middle itself
if (arr[mid] == x)
return mid;
// If element is smaller than mid, then
// it can only be present in left subarray
if (arr[mid] > x)
return binarySearch(arr, l, mid - 1, x);
// Else the element can only be present
// in right subarray
return binarySearch(arr, mid + 1, r, x);
}
// We reach here when element is not present
// in array
return -1;
}
當 x(目標元素)位於排序數組的右半部分時,發生堆棧溢出,我在 Ruby 中收到此錯誤
SystemStackError (stack level too deep)
為什么這發生在 ruby 而不是 java? 我正在 irb 中運行程序。 java 實現直接來自這里https://www.geeksforgeeks.org/binary-search/ 。
首先,讓我們重構您的代碼,使其更加清晰。 注意:此代碼中的行為變化為零,主要是通過一些重構重新格式化。
def binary_search(arr, l, r, x)
return -1 unless r >= 1
mid = l + (r - 1) / 2
case arr[mid] <=> x
when 0 then mid
when -1 then binary_search(arr, mid + 1, r, x)
when 1 then binary_search(arr, l, mid - 1, x)
end
end
二進制搜索有兩個主要問題。
首先是“找不到元素”的終止條件。 二進制搜索的工作方式是將左側“柵欄”移動到右側或將右側“柵欄”移動到左側,具體取決於所需元素在數組中的位置。 這樣,搜索區域變得越來越小。
現在,當兩個“柵欄”相遇(甚至相互擦肩而過)時,就沒有更多的“搜索區域”了,這意味着沒有找到該元素。 However, you are not checking whether the two "fences" meet ( l == r
) or even overtake each other ( l >= r
), you are checking whether r
meets the left boundary of the original array ( r == 1
) .
這意味着您將有很多很多無用的遞歸,直到您最終在找不到元素時放棄。
其實也沒有那么簡單,因為當l
和r
通過時,你的中點計算也是錯誤的,因為現在突然r
小於l
,或者換句話說,右柵欄在左邊左側柵欄的一側!
好吧......除了你的中點計算無論如何都被打破了。 例如,如果l = 10
和r = 12
,兩者之間的中點顯然是mid = 11
,但根據你的公式,它是:
10 + (12 - 1) / 2
10 + ( 11 ) / 2
10 + 5
15
哎呀! 左右之間的中間實際上是向右的右側,這意味着,根據數組中的位置,您的搜索值實際上是在使搜索區域更大而不是更小:您正在將r
回對,這樣您就可以再次搜索您已經搜索過的數組的一部分。 這意味着您在 Ruby 版本中需要比在 Java 版本中更多的遞歸。
l
和r
之間的當前距離公式為r - l
。 現在我們需要一半的距離,即(r - l) / 2
。 如果我們想找到l
和r
之間的中間點,我們需要從l
r
的一半距離,所以我們需要將上述距離添加到l
: l + (r - l) / 2
。
這是固定代碼的樣子:
def binary_search(arr, l, r, x)
return -1 if r < l
mid = l + (r - l) / 2
case arr[mid] <=> x
when 0 then mid
when -1 then binary_search(arr, mid + 1, r, x)
when 1 then binary_search(arr, l, mid - 1, x)
end
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.