1. 程式人生 > >二分查找(binary search)

二分查找(binary search)

內存 數據類型 重要 下標 大小 中間 適用場景 數據 隨機

1 二分查找的思想

每次將待查找元素與區間中間元素進行比較,將查找區間縮減為之前的一半,直到找到待查找元素或查找區間大小為0。

2 實現及關鍵點

2.1 關鍵點

1)循環退出條件

循環退出條件為low <= high,其中low為查找區間的下邊界、high為上邊界,而不是low < high。如果條件為low < high,那麽當查找區間大小為1即low = high時,循環退出就無法與最後一個數據元素進行比較。

2)區間中間索引mid的取值

一般來說mid = (low + high) / 2,但是當low + high超出其數據類型範圍時會造成溢出,所以這樣的mid取值是不穩妥的。mid = low + (high - low) / 2這樣減少了溢出的可能,或者mid = low + ((high - low) >> 1)這樣通過位運算使得計算更加快速。

3)區間上下邊界的更新

更新應為low = mid + 1、high = mid - 1而不是low = mid、high = mid。因為如果是low = mid、high = mid的更新方式,那麽當查找區間為1時而最後的數據元素又不等於查找元素,那麽程序會進入死循環。

2.2 實現

 1 /*查找升序數組中是否存在數據元素num,存在返回其在數組中的位置,不存在則返回-1*/
 2 int BinarySearch(int* pArrNum, int n, int num) {
 3     int low = 0;    //低索引
 4     int high = n - 1
; //高索引 5 int mid; //查找區間中間元素索引 6 7 while (low <= high) { 8 mid = low + ((high - low) >> 1); 9 if (num == pArrNum[mid]) return mid; 10 else if (num > pArrNum[mid]) low = mid + 1; 11 else high = mid - 1; 12 } 13 14 return
-1; 15 }

2.3 復雜度

時間復雜度O(logn),空間復雜度O(1)。

3 適用場景

1)有序數組。二分查找算法依賴於按照下標隨機訪問元素,所以必須是數組;其次,二分查找針對的數據必須是有序的,如果無序要先對其進行排序。

2)數據量太小不適合二分查找。如果數據量太小,例如只有10個數據元素,那麽順序查找就足夠了。但是如果兩個數據元素的比較操作耗時較多時,例如長度較大的字符串比較,那麽還是二分查找合適,因為二分查找比較次數較少。

3)數據量太大不適合二分查找。數組這種數據結構的對內存依賴較大,要求分配連續的內存空間,當數據量較大時很可能會導致內存分配失敗。

4 二分查找的變式

1)查找第一個值等於給定值的元素;

2)查找最後一個值等於給定值的元素;

3)查找第一個大於等於給定值的元素;

4)查找最後一個小於等於給定值的元素;

變體的二分查找問題要註意一下幾個細節:循環退出條件、區間上下界更新方法和返回值選擇。寫二分查找代碼時不要過於追求完美、整潔的寫法,代碼易讀、沒有bug更重要。

 1 /*查找第一個等於給定值的元素,存在返回其在數組中的位置,不存在則返回-1*/
 2 int SearchFirstElem(int* pArrNum, int n, int num) {
 3     int low = 0;
 4     int high = n - 1;
 5     int mid;
 6     int first = -1;    //第一個等於給定值的元素下表
 7 
 8     while (low <= high) {
 9         mid = low + ((high - low) >> 1);
10         if (pArrNum[mid] == num)    first = mid, high = mid - 1;
11         else if (pArrNum[mid] > num)    high = mid - 1;
12         else    low = mid + 1;
13     }
14 
15     return first;
16 }
17 
18 /*查找最後一個等於給定值的元素,存在返回其在數組中的位置,不存在則返回-1*/
19 int SearchLastElem(int* pArrNum, int n, int num) {
20     int low = 0;
21     int high = n - 1;
22     int mid;
23     int last = -1;    //最後一個等於給定值的元素下表
24 
25     while (low <= high) {
26         mid = low + ((high - low) >> 1);
27         if (pArrNum[mid] == num)    last = mid, low = mid + 1;
28         else if (pArrNum[mid] > num)    high = mid - 1;
29         else    low = mid + 1;
30     }
31 
32     return last;
33 }
34 
35 /*查找第一個大於等於給定值的元素,存在返回其在數組中的位置,不存在則返回-1*/
36 int SearchFirstGigOrEqualElem(int* pArrNum, int n, int num) {
37     int low = 0;
38     int high = n - 1;
39     int mid;
40     int first = -1;    //第一個大於等於給定值的元素下表
41 
42     while (low <= high) {
43         mid = low + ((high - low) >> 1);
44         if (pArrNum[mid] >= num)    first = mid, high = mid - 1;
45         else    low = mid + 1;
46     }
47 
48     return first;
49 }
50 
51 /*查找最後一個大於等於給定值的元素,存在返回其在數組中的位置,不存在則返回-1*/
52 int SearchLastLittleOrEqualElem(int* pArrNum, int n, int num) {
53     int low = 0;
54     int high = n - 1;
55     int mid;
56     int last = -1;    //第一個等於給定值的元素下表
57 
58     while (low <= high) {
59         mid = low + ((high - low) >> 1);
60         if (pArrNum[mid] <= num)    last = mid, low = mid + 1;
61         else    high = mid - 1;
62     }
63 
64     return last;
65 }

該篇博客是自己的學習博客,水平有限,如果有哪裏理解不對的地方,希望大家可以指正!

二分查找(binary search)