简单二分查找
function bindarySearch(arr,value){
let low = 0;
let hight = arr.length -1;
while(low <= hight){
let mid = (hight+low)/2;
if(arr[mid] === value) {
return mid;
} else if(arr[mid] < value){
low = mid+1;
} else{
hight = mid-1;
}
}
return -1
}
三点需要注意的:
- while的执行条件:low<=hight;
- mid = (hight+low)/2,如果low和hight很大,可能导致溢出,这里可以改写为low+(hight-low)/2,再进行一次优化,low+((hight-low)>>2),计算机执行位运算比除法运算快
- low和hight的重新赋值:low = mid+1;hight = mid-1;如果直接写成 low=mid 或者 high=mid,就可能会发生死循环
递归写法
function bindarySearch(arr,value,low,hight){
if(low<hight) return -1;
let mid = low + ((hight+low)>>1);// 注意位运算优先级
if(arr[mid] === value) return mid;
if(arr[mid] < value){
return bindarySearch(arr,value,mid+1,hight);
} else {
return bindarySearch(arr,value,low,mid-1);
}
}
function search(arr,value){
let low = 0;
let hight = arr.length -1;
return bindarySearch(arr,value,low,hight);
}
二分查找应用场景的局限性
二分查找的时间复杂度是 O(logn),查找数据的效率非常高。不过,并不是什么情况下都可以用二分查找,它的应用场景是有很大局限性的
- 首先,二分查找依赖的是顺序表结构,简单点说就是数组,不适用于链表,
- 其次,二分查找针对的是有序数据。如果我们针对的是一组静态的数据,没有频繁地插入、删除,我们可以进行一次排序,多次二分查找。这样排序的成本可被均摊,二分查找的边际成本就会比较低。但是,如果我们的数据集合有频繁的插入和删除操作,要想用二分查找,要么每次插入、删除操作之后保证数据仍然有序,要么在每次二分查找之前都先进行排序。针对这种动态数据集合,无论哪种方法,维护有序的成本都是很高的。
- 再次,数据量太小不适合二分查找。
- 最后,数据量太大也不适合二分查找。二分查找的底层需要依赖数组这种数据结构,而数组为了支持随机访问的特性,要求内存空间连续,对内存的要求比较苛刻。比如,我们有 1GB 大小的数据,如果希望用数组来存储,那就需要 1GB 的连续内存空间。
二分查找的变形
1. 变体一:查找第一个值等于给定值的元素
function bindarySearch(arr,value){
let low = 0;
let hight = arr.length -1;
while(low <= hight){
let mid = hight+((hight-low)>>1);
if(arr[mid] < value){
low = mid+1;
} else if{
hight = mid-1;
} else {
// arr[mid] === value;
// 当mid 为0,查找的为第一个,当mid前面一个元素的值 === value说明mid的值不是第一个,继续往前查找
if((mid === 0) || arr[mid-1] !==value){
return mid;
}
hight = mid-1;
}
}
return -1
}
变体二:查找最后一个值等于给定值的元素
function bindarySearch(arr,value){
let low = 0;
let hight = arr.length -1;
while(low <= hight){
let mid = hight+((hight-low)>>1);
if(arr[mid] < value){
low = mid+1;
} else if{
hight = mid-1;
} else {
// arr[mid] === value;
// 当mid 为0,查找的为第一个,当mid前面一个元素的值 === value说明mid的值不是第一个,继续往前查找
if((mid === hight) || arr[mid+1] !==value){
return mid;
}
low = mid+1;
}
}
return -1
}
变体三:查找第一个大于等于给定值的元素
function bindarySearch(arr,value){
let low = 0;
let hight = arr.length -1;
while(low <= hight){
let mid = hight+((hight-low)>>1);
if(arr[mid] >= value){
if ((mid == 0) || (a[mid - 1] < value)) return mid;
high = mid - 1;
} else if{
low = mid+1;
}
}
return -1
}
变体四:查找最后一个小于等于给定值的元素
function bindarySearch(arr,value){
let low = 0;
let hight = arr.length -1;
while(low <= hight){
let mid = hight+((hight-low)>>1);
if(arr[mid] > value){
high = mid - 1;
} else if{
if ((mid == arr.length-1) || (a[mid - 1] > value)) return mid;
low = mid+1;
}
}
return -1
}