四种常见的二分查找变形问题
查找第一个值等于给定值的元素
//查找第一个等于给定值的元素 public static int BSearch2(int[] a, int n, int value){ //定义数组头尾索引 int low = 0, high = n - 1; //循环到头索引大于等于尾索引 while (low <= high){ //位运算头尾索引之和除以二得到mid索引,同时避免溢出 int mid = low + ((high - low) >> 1); //根据大小折半比较范围 if (a[mid] > value) high = mid - 1; else if (a[mid] < value) low = mid + 1; //如果和value相等 else{ //如果mid索引是0,或者mid其前一位不等于value //就说明mid处的数据是第一个和value相等的 if (mid == 0 || a[mid - 1] != value) return mid; //否则就以mid前一位为尾索引进行查找 else high = mid - 1; } } return -1; }
查找最后一个值等于给定值的元素
//查找最后一个等于给定值的元素 public static int BSearch3(int[] a, int n, int value){ //定义数组头尾索引 int low = 0, high = n - 1; //循环到头索引大于等于尾索引 while (low <= high){ //位运算头尾索引之和除以二得到mid索引,同时避免溢出 int mid = low + ((high - low) >> 1); //根据大小折半比较范围 if (a[mid] > value) high = mid - 1; else if (a[mid] < value) low = mid + 1; //如果和value相等 else{ //如果mid索引是n-1,或者mid其后一位不等于value //就说明mid处的数据是最后一个和value相等的 if (mid == n-1 || a[mid + 1] != value) return mid; //否则就以mid后一位为头索引进行查找 else low = mid + 1; } } return -1; }
查找第一个大于等于给定值的元素
//查找第一个大于等于给定值的元素 public static int BSearch4(int[] a, int n, int value){ //定义数组头尾索引 int low = 0, high = n - 1; //循环到头索引大于等于尾索引 while (low <= high){ //位运算头尾索引之和除以二得到mid索引,同时避免溢出 int mid = low + ((high - low) >> 1); //根据大小折半比较范围 //若大于value if (a[mid] > value){ //mid为0或者 if (mid == 0 || a[mid - 1] < value) return mid; else high = mid - 1; } else low = mid + 1; } return -1; }
查找最后一个小于等于给定值的元素
//查找第一个大于等于给定值的元素 public static int BSearch5(int[] a, int n, int value){ //定义数组头尾索引 int low = 0, high = n - 1; //循环到头索引大于等于尾索引 while (low <= high){ //位运算头尾索引之和除以二得到mid索引,同时避免溢出 int mid = low + ((high - low) >> 1); //根据大小折半比较范围 //若大于value if (a[mid] < value){ //mid为0或者 if (mid == n-1 || a[mid + 1] > value) return mid; else low = mid + 1; } else high = mid - 1; } return -1; }
适用性分析
凡是能用二分查找解决的,绝大部分我们更倾向于用散列表或者二叉查找树,
即便二分查找在内存上更节省,但是毕竟内存如此紧缺的情况并不多。
求“值等于给定值”的二分查找确实不怎么用到,二分查找更适合用在”近似“查找问题上。比如上面讲几种变体。
思考
如果有一个有序循环数组,比如4,5,6,1,2,3。针对这种情况,如何实现一个求“值等于给定值”的二分查找算法?