二分查找(递归与非递归)
public class BinarySearch { private BinarySearch() { } //非递归二分查找 public static <T extends Comparable<? super T>> int binarySearch(T[] arr, T key) { int low = 0; int high = arr.length - 1; //查找arr[low...high]是否存在key while (low <= high) { int mid = low + (high - low) / 2; if (arr[mid].compareTo(key) == 0) { return mid; } if (arr[mid].compareTo(key) > 0) { //arr[low...mid-1]是否存在key high = mid - 1; } else { //arr[mid+1...high]是否存在key low = mid + 1; } } return -1; } /*对于mid溢出问题: * 1.long c=a+b; * int mid=c/2; * 2.int mid=(a+b)>>>1; //这是运用a+b不会溢出,是因为int是32位,但是第31位是符号为所以进行位运算时不会溢出 * 3.int mid=a&b+(a^b)>>1; * 目的:两个二进制数,对应位置进行相加,求出每项的项系数,也就是每位结果。 * 1.对应位相等,即同为1,或同为0 * 2.对应为不同,其中一个为1,另一个为0 * 假设先不考虑进位,a+b = 2110211. * 去找规律,发现,情况为2时,相加总为1,相当于异或运算。对于情况1,异或运算总为0. * 再去找规律,发现,情况为1时,两数相与的结果就是两数相加的一半。 * * a:1100110 * b:1010101 * ^:0110011 0 1 4 5 找到了这些项的系数 * &:1000100 2 3 6 找到了这些项的系数 * 但上面这个与运算得出来的并不是真正的项系数,而是对应位置项系数的一般。所以 * 2后得 * :2000200(先不考虑进位) * 所以sum = (a & b) * 2 + (a ^ b) * sum / 2 = (a & b) + (a ^ b) / 2 * */ //递归二分查找 public static <T extends Comparable<? super T>> int binarySearch2(T[] arr, T key, int low, int high) { if (low > high) { return -1; //如果没找到就返回-1 } int mid = low + (high - low) / 2; //数组中间下标,可能会溢出... if (arr[mid] == key) { return mid; } else if (arr[mid].compareTo(key) > 0) { return binarySearch2(arr, key, low, mid - 1); } else { return binarySearch2(arr, key, mid + 1, high); } } }
二分查找(变形一)
public class BinarySerachBian { /** * 二分搜索 * * @param arr * @param target * @param <T> * @return */ public static <T extends Comparable<? super T>> int binarySearch(T[] arr, T target) { int low = 0; int high = arr.length - 1; while (low <= high) { int mid = (low & high) + ((low ^ high) >> 1);//算符优先级:单目乘除位关系,逻辑三目后赋值 if (arr[mid].compareTo(target) == 0) { return mid; } else if (arr[mid].compareTo(target) < 0) { low = mid + 1; } else { high = mid - 1; } } return -1; } /** * 使用分治,查找元素在数组中第一次出现的位置,如果存在就返回相应的位置;如果不存在就返回-1; * * @param arr * @param target * @param <T> * @return */ public static <T extends Comparable<? super T>> int firstFind(T[] arr, T target) { int low = 0; int high = arr.length - 1; while (low < high) { int mid = (low & high) + ((low ^ high) >> 1); if (arr[mid].compareTo(target) < 0) { low = mid + 1; } else { high = mid; } } if (arr[low] == target) { return low; } else { return -1; } } /** * 给定一个数组,和一个target,找出小于target的最接近target的值 * * @param arr * @param terget * @param <T> * @return */ public static <T extends Comparable<? super T>> int findFloor(T[] arr, T terget) { int low = 0; int high = arr.length - 1; while (low <= high) { int mid = (low & high) + ((low ^ high) >> 1); if (arr[mid].compareTo(terget) >= 0) { high = mid - 1; } else { low = mid + 1; } } return high; } }
二分查找(变形二)
//二分查找,若存在返回元素角标,不存在返回一个比key大的最大值的索引值 public static <T extends Comparable<? super T>> int floor(T[] arr, T key) { int low = -1, high = arr.length - 1; while (low < high) { int mid = low + (high - low + 1) / 2; if (arr[mid].compareTo(key) >= 0) { high = mid - 1; } else { low = mid; } } if (low + 1 <= arr.length && arr[low + 1] == key) { return low + 1; } return low; } //二分查找,若存在返回元素角标,不存在返回一个比key大的最小值的索引值 public static <T extends Comparable<? super T>> int ceil(T[] arr, T key) { int low = 0, high = arr.length; while (low < high) { int mid = low + (high - low) / 2; if (arr[mid].compareTo(key) <= 0) { low = mid + 1; } else { high = mid; } } if (high - 1 <= arr.length && arr[high] == key) { return high - 1; } return high; }