整数二分
1. 单调递增序列中找 x 或者 x 的后继
模板一:
a[0]~a[n-1]是单调递增的
int bin_search(int *a, int n, int x)
{
int left = 0, right = n; //注意:不是 n-1,此时是左闭右开的[0,n)
while (left < right)
{
int mid = left + (right-left)/2; //int mid = (left + right) >> 1;
if (x <= a[mid]) right = mid;
else left = mid + 1;
} //终止于left = right
return left; 在这里left是指第几个元素,在某些题可能要-1
}
-
当x <= a[mid]时,说明x在mid的左边,新的搜索区间是左半部分,left不变,更新right = mid
-
当x > a[mid]时,说明x在mid的右边,新的搜索区间是右半部分,right不变,更新left= mid + 1。
-
代码执行完毕后,left= right,两者相等,即答案所处的位置。代码很高效,每次把搜索的范围缩小一半,总次数是log2(n)。
2. 在单调递增序列中查找 x 或者 x 的前驱
模板二:
int bin_search2(int *a, int n, int x)
{ //a[0]~a[n-1]是单调递增的
int left = 0, right = n;
while (left < right)
{
int mid = left + (right-left + 1)/2 ;
if (x >= a[mid]) left = mid;
else right = mid - 1;
} //终止于left = right
return left;
}
- 当x >= a[mid]时,说明x在mid的右边,新的搜索区间是右半部分,所以right不变,更新left= mid;
- 当x < a[mid]时,说明x在mid的左边,新的搜索区间是左半部分,所以left不变,更新right = mid-1
- 同样可以分析出,当x<a[mid]时,不能写成right=mid,会导致while()的死循环。