C++ 二分搜
搜尋(Search)
如何在一群資料裡面查找某個資料 ?
線性搜尋(Linear search): 從頭到尾掃描一次
int target = 9, idx;
int a[] = {5, 4, 9, 1, 2};
for(int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
if(a[i] == target)
idx = i;
}
cout << idx << "\n";Binary search
What if the data is sorted ?
Binary search
對於每個在陣列裡的數,他不是大於等於target,就是小於target
Binary search
對於每個在陣列裡的數,他不是大於等於target,就是小於target
設target=38
data=[2, 11, 24, 35, 38, 39, 44, 47, 51, 55, 72, 75, 82, 85, 91, 96]
[2, 11, 24, 35, 38, 39, 44, 47, 51, 55, 72, 75, 82, 85, 91, 96]
[2, 11, 24, 35, 38, 39, 44, 47, 51, 55, 72, 75, 82, 85, 91, 96]
[2, 11, 24, 35, 38, 39, 44, 47, 51, 55, 72, 75, 82, 85, 91, 96]
[2, 11, 24, 35, 38, 39, 44, 47, 51, 55, 72, 75, 82, 85, 91, 96]
[2, 11, 24, 35, 38, 39, 44, 47, 51, 55, 72, 75, 82, 85, 91, 96]
[2, 11, 24, 35, 38, 39, 44, 47, 51, 55, 72, 75, 82, 85, 91, 96]
[2, 11, 24, 35, 38, 39, 44, 47, 51, 55, 72, 75, 82, 85, 91, 96]
Steps
-
從區間的中點開始比較。
-
如果目標值等於中點,搜尋結束。
-
如果目標值小於中點,則縮小到左半邊繼續找;否則縮小到右半邊。
-
每次都把搜尋範圍縮小一半,直到找到或區間為空。
Remark: 我們是在尋找index,透過index可以拿到資料
target 要在範圍裡面
int binary_search(int a[], int target, int n) {
int l = 0, r = n; // [l, r)
while (l < r) {
int mid = (l + r) / 2;
if (a[mid] == target) return mid;
else if (a[mid] < target) l = mid + 1;
// 丟掉 [l, mid]
else r = mid;
// 丟掉 [mid, r)
}
return -1;
}Binary search
二分搜常見錯誤
- 開閉區間沒定義好
- mid 沒有寫對導致target沒有出現在區間裡面
左閉右閉 [l, r]
int binary_search(int a[], int target, int n) {
int l = 0, r = n - 1; // [0, n - 1] 都在陣列裡面
while (l < r) {
int mid = (l + r) / 2;
if (a[mid] == target)
return mid; // 找到
else if (a[mid] < target)
l = mid + 1;
else
r = mid - 1;
}
return -1; // 沒找到
}Remark: target一定要在 [l, r] 裡面
左閉右開 [l, r)
int binary_search(int a[], int target, int n) {
int l = 0, r = n; // n沒有在陣列裡面
while (l < r) {
cout << l <<" " << r <<"\n";
int mid = (l + r) / 2;
if (a[mid] < target)
l = mid + 1; //注意是mid + 1
else
r = mid;
}
return l;
}Remark: target一定要存在 [l, r) 裡面
當 l == r時 區間已經空了,不用再檢查
Upper_bound
Upper_bound: 第一個大於 target 的元素位置 a[idx] > target
target: 6
array: {1, 1, 2, 3, 5, 5, 6, 6, 7, 9, 13, 15}
idx: 8嘗試用左閉右開寫出upper_bound
Upper_bound
goal: find idx such that a[idx] > target
Case 1: a[mid] <= target [l, mid] 不會是答案, 答案在[mid + 1, r)裡面 Case 2: a[mid] > target 答案是mid 或是在 [l, mid) 裡面
Upper_bound
int upper_bound(int a[], int target, int n) {
int l = 0, r = n; // [0, n) n沒有在陣列裡面
while (l < r) {
int mid = (l + r) / 2;
if(a[mid] <= target)
l = mid + 1;
else
r = mid;
}
return l; //最後l會等於r
}Lower_bound
Lower_bound: 第一個大於等於 target 的元素位置 a[idx] >= target
target: 6
array: {1, 1, 2, 3, 5, 5, 6, 6, 7, 9, 13, 15}
idx: 6嘗試用左閉右開寫出lower_bound
lower_bound
goal: find idx such that a[idx] >= target
Case 1: a[mid] < target [l, mid] 不會是答案, 答案在[mid + 1, r)裡面 Case 2: a[mid] >= target 答案是mid 或是在 [l, mid) 裡面
lower_bound
int lower_bound(int a[], int target, int n) {
int l = 0, r = n; // [0, n) n沒有在陣列裡面
while (l < r) {
int mid = (l + r) / 2;
if(a[mid] < target)
l = mid + 1; // mid 太小,丟掉左半
else
r = mid;
// mid >= target,可能是答案,縮小右邊界
}
return l;
// l == r,答案是第一個 >= target 的位置
}練習
C++ 二分搜
By ernestii26
C++ 二分搜
- 15