文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

面试官:说说你对二分查找的理解?如何实现?应用场景?

2024-12-02 20:10

关注

一、是什么

在计算机科学中,二分查找算法,也称折半搜索算法,是一种在有序数组中查找某一特定元素的搜索算法

想要应用二分查找法,则这一堆数应有如下特性:

搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束

如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较

如果在某一步骤数组为空,则代表找不到

这种搜索算法每一次比较都使搜索范围缩小一半

如下图所示:

相比普通的顺序查找,除了数据量很少的情况下,二分查找会比顺序查找更快,区别如下所示:

二、如何实现

基于二分查找的实现,如果数据是有序的,并且不存在重复项,实现代码如下:

  1. function BinarySearch(arr, target) { 
  2.     if (arr.length <= 1) return -1 
  3.     // 低位下标 
  4.     let lowIndex = 0 
  5.     // 高位下标 
  6.     let highIndex = arr.length - 1 
  7.  
  8.     while (lowIndex <= highIndex) { 
  9.         // 中间下标 
  10.         const midIndex = Math.floor((lowIndex + highIndex) / 2) 
  11.         if (target < arr[midIndex]) { 
  12.             highIndex = midIndex - 1 
  13.         } else if (target > arr[midIndex]) { 
  14.             lowIndex = midIndex + 1 
  15.         } else { 
  16.             // target === arr[midIndex] 
  17.             return midIndex 
  18.         } 
  19.     } 
  20.     return -1 

如果数组中存在重复项,而我们需要找出第一个制定的值,实现则如下:

  1. function BinarySearchFirst(arr, target) { 
  2.     if (arr.length <= 1) return -1 
  3.     // 低位下标 
  4.     let lowIndex = 0 
  5.     // 高位下标 
  6.     let highIndex = arr.length - 1 
  7.  
  8.     while (lowIndex <= highIndex) { 
  9.         // 中间下标 
  10.         const midIndex = Math.floor((lowIndex + highIndex) / 2) 
  11.         if (target < arr[midIndex]) { 
  12.             highIndex = midIndex - 1 
  13.         } else if (target > arr[midIndex]) { 
  14.             lowIndex = midIndex + 1 
  15.         } else { 
  16.             // 当 target 与 arr[midIndex] 相等的时候,如果 midIndex 为0或者前一个数比 target 小那么就找到了第一个等于给定值的元素,直接返回 
  17.             if (midIndex === 0 || arr[midIndex - 1] < target) return midIndex 
  18.             // 否则高位下标为中间下标减1,继续查找 
  19.             highIndex = midIndex - 1 
  20.         } 
  21.     } 
  22.     return -1 

实际上,除了有序的数组可以使用,还有一种特殊的数组可以应用,那就是轮转后的有序数组

有序数组即一个有序数字以某一个数为轴,将其之前的所有数都轮转到数组的末尾所得

例如,[4, 5, 6, 7, 0, 1, 2]就是一个轮转后的有序数组

该数组的特性是存在一个分界点用来分界两个有序数组,如下:

分界点有如下特性:

代码实现如下:

  1. function search (nums, target) { 
  2.   // 如果为空或者是空数组的情况 
  3.   if (nums == null || !nums.length) { 
  4.     return -1; 
  5.   } 
  6.   // 搜索区间是前闭后闭 
  7.   let begin = 0, 
  8.     end = nums.length - 1; 
  9.   while (begin <= end) { 
  10.     // 下面这样写是考虑大数情况下避免溢出 
  11.     let mid = begin + ((end - begin) >> 1); 
  12.     if (nums[mid] == target) { 
  13.       return mid; 
  14.     } 
  15.     // 如果左边是有序的 
  16.     if (nums[begin] <= nums[mid]) { 
  17.       //同时target在[ nums[begin],nums[mid] ]中,那么就在这段有序区间查找 
  18.       if (nums[begin] <= target && target <= nums[mid]) { 
  19.         end = mid - 1; 
  20.       } else { 
  21.         //否则去反方向查找 
  22.         begin = mid + 1; 
  23.       } 
  24.       //如果右侧是有序的 
  25.     } else { 
  26.       //同时target在[ nums[mid],nums[end] ]中,那么就在这段有序区间查找 
  27.       if (nums[mid] <= target && target <= nums[end]) { 
  28.         begin = mid + 1; 
  29.       } else { 
  30.         end = mid - 1; 
  31.       } 
  32.     } 
  33.   } 
  34.   return -1; 
  35. }; 

对比普通的二分查找法,为了确定目标数会落在二分后的哪个部分,我们需要更多的判定条件

三、应用场景

二分查找法的O(logn)让它成为十分高效的算法。不过它的缺陷却也是比较明显,就在它的限定之上:

有序:我们很难保证我们的数组都是有序的

数组:数组读取效率是O(1),可是它的插入和删除某个元素的效率却是O(n),并且数组的存储是需要连续的内存空间,不适合大数据的情况

关于二分查找的应用场景,主要如下:

不适合数据量太小的数列;数列太小,直接顺序遍历说不定更快,也更简单

每次元素与元素的比较是比较耗时的,这个比较操作耗时占整个遍历算法时间的大部分,那么使用二分查找就能有效减少元素比较的次数

不适合数据量太大的数列,二分查找作用的数据结构是顺序表,也就是数组,数组是需要连续的内存空间的,系统并不一定有这么大的连续内存空间可以使用

参考文献

https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%88%86%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95#javascript_%E7%89%88%E6%9C%AC

 

https://www.cnblogs.com/ider/archive/2012/04/01/binary_search.html

 

来源:JS每日一题内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯