C++左閉右開區間的理解
阿新 • • 發佈:2019-02-14
C++的區間是左閉右開的,關於這樣做的優勢,做了一個筆記整理,也處理下之前一直比較模糊的區間二分的問題。
左閉右開的區間第一個優勢是,當需要取中間元素的時候,mid=begin+end/2
的定位問題。如果區間元素的個數是奇數個,那麼mid
永遠是指向中間的元素;如果區間元素是偶數個,那麼mid
永遠指向後半段區間的首元素。這樣做在二分查詢等一些演算法的實現上特別有優勢。mid
的另一個等效的寫法是mid=begin+(end-begin)/2
。
比如區間的下標是0,1,2,3
,是偶數個,那麼begin=0,end=4
,所以mid=(begin+end)/2=(0+4)/2=2
,正好是後半段首元素。再看區間下標是0,1,2,3,4
begin=0,end=5
,所以mid=(begin+end)/2=(0+5)/2=2
,此時2正好是中間的元素。在任意合理的區間
[begin,end)
上,總是有mid=(begin+end)/2
把區間分成[begin,begin+mid)
和[mid,end)
兩個部分。
第二個優勢在於方便迭代器快速的進行終止判別。使用左閉右開的區間,迭代終止的條件是begin==end
(或者begin>=end
),這樣僅需要一個條件就能終止迭代判斷。
第三個優勢在於快速統計區間元素的個數,n=end-begin
即為元素的個數。
上述兩個優勢對於特殊情況,只有一個或者兩個元素的區間(這一般發生在二分之類的演算法快要終止的時候),也有更好的效果。如果當前只剩下一個元素,位置是index
[index,index+1)
,因為這是奇數個元素,所以mid=(2*index+1)/2=index
,所以前半個區間是mid
元素,後半段區間是空。如果有兩個元素,[index,index+1]
,那麼mid=(2*index+2)/2=index+1
,正好把區間分成兩個元素,又回到了僅有一個元素的情況了。
根據上述的描述,可以更好的理解二分演算法了:
#include <iostream> using std::cout; using std::cin; using std::endl; int BinarySearch(int Arr[], int first, int last, int val) { while(first != last) { // 終止條件 int mid = first + (last - first) / 2; // 區間二分 // int mid = (first + last) / 2; // 另一種等效的寫法 if(Arr[mid] == val) { // 找到 return mid; } else if(mid > val) { // 左側區間 last = mid; } else { // 右側區間 first = mid + 1; } } return -1; // 沒找到 } int main() { int A1[5] = {0, 1, 2, 3, 4}; cout << "--------------測試奇數個元素----------------\n"; for(int i = 0; i < 5; ++i) { cout << BinarySearch(A1, 0, 5, i) << endl; } cout << BinarySearch(A1, 0, 4, -1) << endl; cout << BinarySearch(A1, 0, 4, 5) << endl; int A2[5] = {0, 1, 2, 3}; cout << "--------------測試偶數個元素----------------\n"; for(int i = 0; i < 5; ++i) { cout << BinarySearch(A2, 0, 4, i) << endl; } cout << BinarySearch(A2, 0, 4, -1) << endl; cout << BinarySearch(A2, 0, 4, 4) << endl; return 0; }