一、概述
二分查找是针对有序数列的,对无序数列是无效的,在有序序列中使用二分查找能大大提高查找效率,通常能将时间按复杂度从O(n)降至O(logn)。
二、查找某数的位置(或存在性)
递归:
1 //返回"-1"表示为找到 2 //否则返回目标的下标(若有多个,只是其中一个) 3 int binary_searchs(int *arr, int target, int l, int r) 4 { 5 if (l > r) return -1; 6 int mid = (l + r) >> 1; 7 if (arr[mid] == target) 8 return mid; 9 else if (arr[mid] > target) 10 binary_search(arr, target, l, mid - 1); 11 else 12 binary_search(arr, target, mid + 1, r); 13 }
非递归:
1 //返回"-1"表示为找到 2 //否则返回目标的下标(若有多个,只是其中一个) 3 int binary_searchs(int * arr, int x, int l, int r) 4 { 5 int lt = l, rt = r; 6 while (lt <= rt) 7 { 8 int mid = (lt + rt) >> 1; 9 if (arr[mid] == x) return mid; 10 else if (arr[mid] < x) 11 lt = mid + 1; 12 else 13 rt = mid - 1; 14 } 15 return -1; 16 }
三、查找某数出现的次数
递归:
1 //返回target的出现次数 2 //返回0意味着不存在 3 int binary_search(int *arr, int target, int l, int r) 4 { 5 if (l > r) return 0; 6 int mid = (l + r) >> 1; 7 if (arr[mid] == target) 8 return 1 + binary_search(arr, target, l, mid - 1) + binary_search(arr, target, mid + 1, r); 9 else if (arr[mid] > target) 10 binary_search(arr, target, l, mid - 1); 11 else 12 binary_search(arr, target, mid + 1, r); 13 }
递归(优化版):如果有序数列中,目标元素占大多数,二分法会退化成逐一遍历,O(logn)增至O(n),我们要预防这种情况,所以当找到目标元素时,尽可能向两边去找目标元素。
1 //返回target的出现次数 2 //返回0意味着不存在 3 int binary_search(int *arr, int target, int l, int r) 4 { 5 if (l > r) return 0; 6 int mid = (l + r) >> 1; 7 if (arr[mid] == target) 8 { 9 int cnt1, cnt2; 10 cnt1 = cnt2 = mid; 11 if (((cnt1 - 1) >= l) && (arr[cnt1] == arr[cnt1 - 1])) cnt1--; 12 if (((cnt2 + 1) <= r) && (arr[cnt2] == arr[cnt2 + 1])) cnt2++; 13 return 1 + (cnt2 -cnt1) + binary_search(arr, target, l, cnt1 - 1) + binary_search(arr, target, cnt2 + 1, r); 14 } 15 else if (arr[mid] > target) 16 binary_search(arr, target, l, mid - 1); 17 else 18 binary_search(arr, target, mid + 1, r); 19 }
非递归:我觉得这个非递归不好写,主要是找到目标元素时,在前一部分和后一部分也有可能存在目标元素,不用递归的方式不好写。以后写出来了再来补吧。
非递归被同学写出来了,在此补上
1 int binary_searchs(int *arr, int target,int l, int r) 2 { 3 int res = 0; 4 while (l <= r) 5 { 6 int mid = (l + r) >> 1; 7 if (arr[mid] == target) 8 { 9 if (l == r) 10 { 11 res++; 12 break; 13 } 14 for (int i = mid + 1; i <= r; i++) 15 if (arr[mid] == arr[i]) 16 res++; 17 for (int i = mid - 1; i >= l; i--) 18 if (arr[mid] == arr[i]) 19 res++; 20 res++; 21 break; 22 } 23 else if (arr[mid] < target) 24 l = mid + 1; 25 else if (arr[mid] > target) 26 r = mid - 1; 27 } 28 return res; 29 }