二分查找是必须要掌握的技能,适用于有序的、顺序的存储结构。
1、可以用它来查找某一个数
2、可以用于查找某一个范围。如《二分查找有序数组中某个数的所在范围 Search for a Range》。
3、可以用它来查找两个有序数组的中位数。
4、本文中,二分查找又多了一项新的本领,可以用它在循环有序数组中查找某个数。
二分查找的关键,在于求出中间下标mid之后,我能判断出key在mid的哪一侧,然后去那一侧找。
循环有序数组:
指的是,将一个有序数组循环左/右移动若干距离之后变成的数组。如,[1,2,3,4,5]循环右移3位,就成为[4,5,1,2,3]。该数组的特点是,其中包含着一个转折点。转折点左右两侧的子数组都是有序的,并且左侧的子数组整体都比右侧的子数组大。
查找方法:
不要想着直接定位到转折点。
只需要知道转折点在中间点的哪一侧就行。因为不含转折点的一侧一定是单调递增的,依然能够帮助我判断出key在mid的哪一侧。
根据left和right下标,求得mid下标。
如果A[left]<=A[mid],那么A[mid]一定不在转折点左侧,意味着从left到mid的整个左半部分都是严格递增的,因此我能够判断key是否在左半部分里。
如果A[left]>A[mid],那么A[mid]一点在转折点左侧,意味着从mid到right的整个右半部分是严格递增的,因此我能够判断key是否在右半部分里。
实现一(数组中不包含重复元素):
- class Solution {
- public:
-
- int search(int A[], int n, int target)
- {
- if(n<=0)
- return -1;
- int left = 0, right = n-1;
- while(left<=right)
- {
- int mid = left + ((right-left)/2);
- if(A[mid] == target)
- return mid;
-
- if(A[left] <= A[mid])
- {
- if(A[left] <= target && target < A[mid])
- right = mid - 1;
- else
- left = mid + 1;
- }
- else
- {
- if(A[mid] < target && target <= A[right])
- left = mid + 1;
- else
- right = mid - 1;
- }
- }
- return -1;
- }
-
- };
上面的方法没有考虑数组中有重复元素的情形。
实现二(数组中可能出现重复元素):
- class Solution {
- public:
- bool search(int A[], int n, int target) {
- return bisearch(A, 0, n-1, target);
- }
-
- bool bisearch(int A[], int left, int right, int target)
- {
- if(left > right)
- return false;
- int mid = left + (right - left)/2;
- if(target == A[mid])
- return true;
-
-
- if(A[mid] > A[left] && A[mid] < A[right])
- {
- if(target < A[mid])
- return bisearch(A, left, mid-1, target);
- else
- return bisearch(A, mid+1, right, target);
- }
-
- else if(A[mid] < A[left] && A[mid] < A[right])
- {
- if(target > A[mid] && target <= A[right])
- return bisearch(A, mid+1, right, target);
- else
- return bisearch(A, left, mid-1, target);
- }
-
- else if(A[mid] > A[left] && A[mid] > A[right])
- {
- if(target < A[mid] && target >= A[left])
- return bisearch(A, left, mid-1, target);
- else
- return bisearch(A, mid+1, right, target);
- }
-
- else
- {
- return bisearch(A, left, mid-1, target) || bisearch(A, mid+1, right, target);
- }
-
- }
-
-
- };