一起手写吧!二分查找!
二分查找,也称折半查找。利用二分思想,每次查找的时候把数据分为两半,从中间值开始找。
如上图所示,low和high代表数组的两边下标,mid代表数组的中间下标。
-
若目标值比中间值大,即目标值在mid与high之间,就修改low的值。再对比中间值。
-
若目标值比中间值小,即目标值在low与mid之间,就修改high的值。再对比中间值。
上述就是二分查找的过程,那它的时间复杂度怎么求呢❓
假设数组的长度为n,那么查找一次后长度变为n/2,再查找一次后长度变为n/4,以此类推,最坏情况下,n/2^k为空,查找停止。于是我们有以下的公式:
n * n/2 * n/4 * n/8 * n/2^k ·····
以上是一个等比数列,n / 2^k = 1时,k就是查找的次数。即k=log2n,所以时间复杂度为O(logn),这是一种非常高效率的算法。
非递归版
function binary_search(arr, key) { var low = 0, high = arr.length - 1; while(low <= high){ var mid = parseInt(low + (high - low) / 2); if(key === arr[mid]){ return mid; } else if (key > arr[mid]){ low = mid + 1; } else if (key < arr[mid]){ high = mid -1; } else { return -1; } } }; var arr = [5,13,19,21,37,56,64,75,80,88,92]; var result = binary_search(arr, 21); console.log(result);
需要注意的是,mid的取值不要写成(low + high) / 2,因为如果low+high很大的话,会溢出。因此写成low+(high-low)/2就不会有这个问题。
更进一步,当然也可以用位运算来low+((high-low)>>1)代替low+(high-low)/2,而且这种位运算的效率更高一些。
递归版
二分查找除了上边介绍的循环方法外,还可以用递归来实现。
function binary_search(arr,low, high, key) { if (low > high){ return -1; } var mid = low + ((high - low) >> 1); if(arr[mid] == key){ return mid; }else if (arr[mid] > key){ high = mid - 1; return binary_search(arr, low, high, key); }else if (arr[mid] < key){ low = mid + 1; return binary_search(arr, low, high, key); } }; var arr = [5,13,19,21,37,56,64,75,80,88,92]; var result = binary_search(arr,0, 11, 21); console.log(result);
3.数组中存在重复的数据,怎么找出元素最后一次出现的位置
和上边介绍的二分查找思路一样:
function binary_search(arr, key) { var low = 0, high = arr.length - 1; while (low <= high) { var mid = low + ((high - low) >> 1); if (arr[mid] > key) { high = mid - 1; } else if (arr[mid] < key) { low = mid + 1; } else { if ((mid == arr.length - 1) || (arr[mid + 1] != key)) return mid; else low = mid + 1; } } return -1; } var arr = [5,13,19,21,21,37,56,64,75,80,88,92]; var result = binary_search(arr, 21); console.log(result);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术