一、二分查找的思想
二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。
二分查找的效率非常之高,时间复杂度为O(log(N)),这是一个相当惊人的时间复杂度。
二、二分查找的递归和非递归实现
一.递归实现
递归调用方法实现
二.非递归实现
while循环实现
三.递归和非递归的代码实现
package binarysearch;
public class binarySearchDemo {
public static void main(String[] args) {
//已经排好序的数组
int[] MergeArray = {8, 11, 19, 23, 27, 33, 45, 55, 67, 98};//
//需要寻找得值
int tagret1 = 67;
int tagret2 = 8;
//排序方法
binarySearchByRecursion(MergeArray, tagret2, 0, MergeArray.length - 1);
binarySearchByWhile(MergeArray, tagret1, 0, MergeArray.length - 1);
}
//递归算法
public static void binarySearchByRecursion(int[] MergeArray, int tagret, int indexlow, int indexhigt) {
//1如果目标数据小于当前范围最小数据。2目标数据大于当前范围最大数据
if (tagret > MergeArray[indexhigt] || tagret < MergeArray[indexlow]) {
return;
}
int indexMiddle = indexlow + (indexhigt - indexlow) / 2;
if (MergeArray[indexMiddle] > tagret) {
binarySearchByRecursion(MergeArray, tagret, indexlow, indexMiddle - 1);
} else if (MergeArray[indexMiddle] < tagret) {
binarySearchByRecursion(MergeArray, tagret, indexMiddle + 1, indexhigt);
} else if (MergeArray[indexMiddle] == tagret) {
System.out.printf("找到目标数据" + MergeArray[indexMiddle]);
} else {
System.out.println("目标数据不在数据范围内");
}
}
//WHILE查找
public static void binarySearchByWhile(int[] MergeArray, int tagret, int indexlow, int indexhigt) {
if (indexlow > indexhigt) {
return;
}
while (indexlow <= indexhigt) {
int indexMiddle = indexlow + (indexhigt - indexlow) / 2;
if (indexhigt == indexlow && indexhigt - indexlow == 0) {
if (MergeArray[indexMiddle] == MergeArray[indexlow]) {
System.out.printf("找到目标数据" + MergeArray[indexMiddle]);
return;
}
} else if (MergeArray[indexMiddle] > tagret) {
indexhigt = indexMiddle - 1;
} else if (MergeArray[indexMiddle] < tagret) {
indexlow = indexMiddle + 1;
} else if (MergeArray[indexMiddle] == tagret) {
System.out.printf("找到目标数据" + MergeArray[indexMiddle]);
return;
} else {
System.out.println("目标数据不在数据范围内");
return;
}
}
}
}
三、二分查找的易错点
一.循环退出条件
注意是 low<=high,而不是 low
二.mid 的取值
改进的方法是将 mid 的计算方式写成 low+(high-low)/2。更进一步,如果要将性能优化到极致的话,可以将这里的除以 2 操作转化成位运算 low+((high-low)>>1)。
三.low 和 high 的更新
low=mid+1,high=mid-1。注意这里的 +1 和 -1,如果直接写成 low=mid 或者 high=mid,就可能会发生死循环。比如,当 high=3,low=3 时,如果 a[3]不等于 value,就会导致一直循环不退出。
四、二分查找的局限性
一.二分查找依赖的是顺序表结构
二分查找只能用在数据是通过顺序表来存储的数据结构上。如果你的数据是通过其他数据结构存储的,则无法应用二分查找。
二.二分查找针对的是有序数据
二分查找对这一点的要求比较苛刻,数据必须是有序的。如果数据没有序,需要先排序。
三.数据量太小不适合二分查找
如果要处理的数据量很小,完全没有必要用二分查找,顺序遍历就足够了。比如我们在一个大小为 10 的数组中查找一个元素,不管用二分查找还是顺序遍历,查找速度都差不多。只有数据量比较大的时候,二分查找的优势才会比较明显。
四.数据量太大也不适合二分查找
二分查找的底层需要依赖数组这种数据结构,而数组为了支持随机访问的特性,要求内存空间连续,对内存的要求比较苛刻。比如有 1GB 大小的数据,如果希望用数组来存储,那就需要 1GB 的连续内存空间。