基于有序数组的二分查找:
算法思想:
取中间的索引,用目标索引 和 中间索引上的元素 进行比较。如果中间索引和我们查找的值相同,返回该索引。如果被查找的目标元素小于中间索引元素,我们就从左子数组上查找,否则从右子数组上查找。
二分查找法的思路在1946年提出,大家觉得它是一个很简单的算法,然而从思想提出到第一个没有bug的代码实现,整个世界花了16年。你对此算法的态度是什么?
算法实现(迭代版本):
package com.cosyit.offer.algorithms.find;
import java.util.Objects;
public class BinarySearch {
/**
* 二分查找法,在有序数组a中,查找target。
* 此代码的要求:给你一张纸张+有限的思维训练 在纸上面就可以写出来。
* @param a 数组
* @param target 查找元素
* @return 返回所在的元素索引index
*/
public static int binarySearch(Comparable[] a, Comparable target) {
//在 已经排好序的 a[l,r] 中查找 target.
int l = 0, r = a.length - 1;
while (l <= r) {
// int mid = (l + r) / 2; //中间元素mid. // 这个地方,2个大int 相加会溢出,有这个bug.
int mid = l + (r - l) / 2; // 这样就没bug了。
int compare = target.compareTo(a[mid]);
if (compare == 0) return mid;
if (compare < 0)
r = mid - 1; // mid -1 ? 因为上一个if 中我们已经判断了相等的情况,能执行到此处,肯定是不相等的。那么只能在 l...mid-1 这个范围中查找。
else
l = mid + 1;// 为什么+1,原因同上。
}
return -1; //没找到return -1 .
}
public static void main(String[] args) {
Integer [] a = {1,2,3,4,5,7,9,22,33,44,55,81};
Integer target = 33;
int index = binarySearch(a, target);
System.out.println(index);
System.out.println(Objects.equals(a[index], target));
}
}
递归版本的实现:
package com.cosyit.offer.algorithms.find;
/**
* 二分查找递归方式。
* @author wangdawei
*/
public class BinarySearch {
/**
* @param key 查找对象 --->字
* @param a 查找的数组--->字典
* @return 数组中的位置--->在哪里
*/
public static int binarySearch(int key, int[] a) {
return __binarySearch(key, a, 0, a.length - 1);
}
/**
* 33 -> 1 - 50 - 100
* 找到33所在的位置。
*/
public static int __binarySearch(int target, int[] a, int lo, int hi) {
if (lo > hi) {
return -1;
}
//防止 大int相加而产生的bug问题。
int mid = lo + (hi - lo) / 2;
//比较中间索引上的值。
if (target < a[mid]) {
return __binarySearch(target, a, lo, mid - 1);
} else if (target > a[mid]) {
return __binarySearch(target, a, mid + 1, hi);
} else {
//只有当查找元素=a[mid]
return mid;
}
}
public static void main(String[] args) {
int[] arr = new int[10_0000];
for (int i = 0; i < arr.length; i++) {
arr[i] = i + 1;
}
System.out.println(binarySearch(55555, arr));
}
}