一、简介
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
二、查找过程
首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
用于二分查找的数组前提是排好序的,先将要查找元素与侍比较数组的中间元素比较,如果大于中间元素则将比较范围缩小到中间元素+1到末尾元素,如果小于中间元素则将范围缩小到开始元素到中间元素-1。以此规则不断比较直到找到侍查找元素为止,循环的停止条件为start<end表明在将所有元素查找了一遍之后仍末找到侍查找元素,结束循环。
优点:比较元素少,查找速度快,平均性能好。
缺点:要求侍查找表为有序表。
三、图示说明(图片来源网络)
四、两种实现方式
时间复杂度:
最好情况下为O(1)
最坏情况下两种方式复杂度相同为:O(log2 N)
空间复杂度:
非递归方式,由于辅助空间是常数级别的所以,空间复杂度是O(1)。
递归方式:递归的次数和深度老师log2N,每次所需要的辅助空间都是常数级的:O(log2N)
1、非递归方式
public class BinarySearch {
public static void main(String[] args) {
//测试用例
int[] arr = {2,4,5,6,8,9,12,14,23,34,46,57,68,69,78};
int key = binarySearch(arr,11);
System.out.println(key);
}
private static int binarySearch(int[] arr,int key) {
int start = 0;
//因为数组下标从0开始,所以结尾是arr.length-1;
int end = arr.length-1;
int middle = 0;
while(start<=end) {
//每次没有找到时middle被重新赋值,并且用于之后的循环
middle= (start+end)/2;
//如果侍查找元素等于数组中间数,则直接返回数组下标
if (key==arr[middle]) {
return middle;
//如果侍查找元素大于数组中间数,则将范围缩小到后一半
}else if (key>arr[middle]) {
start = middle+1;
//如果侍查找元素小于数组中间数,则将范围缩小到前一半
}else if(key<arr[middle]){
end = middle-1;
}
}
return -1;
}
}
2、递归方式
private static int recursionBinarySearch(int[] arr,int key,int start,int end) {
if (key<arr[start]||key>arr[end]||start>end) {
return -1;
}
int middle = (start+end)/2;
if (key>arr[middle]) {
return recursionBinarySearch(arr, key, middle+1, end);
}else if (key<arr[middle]) {
return recursionBinarySearch(arr, key, start, middle-1);
}else {
return middle;
}
}