二分查詢的迴圈條件及指標終止位置問題
常見的二分搜尋法的迴圈迭代方法分為:左閉右開 和 左閉右閉 兩種方式
-
左閉右開:由於右邊界開放,例如[1,1)是矛盾的,因此迴圈條件為
while(l<r)
。閉合指後續迭代仍需要進行對其元素進行比較。因此每次迭代結束,左指標l
移動到中點的下一位l = mid+1
,而不需要移動到中點位置,因為中點位置已被和目標值比較過;開放意味著後續不需要再進行比較,因此每次右指標r
需要移動到已經比較過的中點位置mid
; -
左閉右閉:由於右邊界閉合,例如[1,1]是合理的,因此迴圈條件為
while(l<=r)
;由於左右邊界都閉合,這意味著後續迭代需要對左右邊界即l
和r
指向的元素進行判斷。因此每次迭代結束,左指標l
移動到中點的下一位l = mid+1
,右指標r
移動到中點的前一個位置r = mid-1
,因為mid
位置已經被比較過了。
詳細解釋為什麼
while(l<r)
時需要右指標r
移動到mid
,而while(l<=r)
時需要右指標r
移動到mid-1
:首先,這兩種情況下,每次迴圈的不變數都是左指標要移動到mid
的下一位(左閉)。
-
當
while(l<r)
時,我們考慮l+1=r
這種情況,即l
指標位於r
指標的前一位,此時mid
指向l
:(1)若目標值target < nums[mid]=nums[l]
,此時r
指標移動到mid
也就是l
的位置,l=r
正常結束。(2)若目標值target > nums[mid]=nums[l]
,l
指標移動到mid
的下一位r
的位置,此時l=r
迴圈結束,但r
指向的元素未被判斷。這就要求我們在先前已經對右指標r
指向的元素進行過判斷,結束才是合理的。因此,因此當移動右指標時,我們必須保證右指標指向的元素是在先前已經被判斷過的,所以每次右指標要移動到mid
的位置,若移動到mid-1
,那麼r
指標指向的位置就沒有被判斷,在上述情況下,就是錯誤的結束。同時這就是 右開 的由來,每次迴圈不用判斷r
指向的元素,因為它在上次移動到的是已經比較過的元素的位置。 -
當
while(l<=r)
,同樣考慮l+1=r
這種情況:(1)情況同上相同。(2)當目標值target > nums[mid]=nums[l]
時,l
指標移動到mid
的下一位r
的位置,l=r
仍未結束,此時mid=l=r
對r進行判斷。這意味著右指標r
指向的元素在後續會被判斷到,這就要求,我們每次迭代改變右指標r
的位置時,是先前未被判斷過的即可,即每次r指標移動到mid-1
的位置。這是 右閉 的由來,因為右邊界r
的指向未被比較過,需要在後續比較。
mid = ( l + r ) / 2下,指標終止情況
針對以上兩種迴圈迭代方法,本文列舉了所有指標終止位置的情況。其中包括不引入輔助元素、引入左邊界輔助元素、引入右邊界輔助元素以及同時引入左右邊界輔助元素時,左右指標的終止位置情況。旨在將規律具象化,便於理解。(注:在不越界的情況下,令 mid = ( l + r ) / 2)
不引入輔助元素
引入左邊界
引入右邊界
引入左右邊界
總結
左閉右開:
- 在不引入輔助邊界的情況下,除了大於右邊界的目標值,左右指標
l
和r
共同指向第一個大於目標的數 - 當引入了右輔助邊界時,左右指標
l
和r
共同指向第一個大於目標的數。
左閉右閉:
- 無論是否引入左右輔助邊界,右指標
r
始終指向小於目標的最近位置的數,左指標l
始終指向大於目標的最近位置的數