前言

二分查找算法也称为折半查找算法,是一种在查找算法中普遍使用的算法。其算法的基本思想是:在有序表中,取中间的记录作为比较关键字,若给定值与中间记录的关键字相等,则查找成功;若给定的值小于中间记录的关键字,则在中间记录的左半区间继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区间继续查找;不断重复这个过程,直到查找成功。否则查找失败。这个思想与孔子中的中庸思想和相似。

二分查找算法的实现

基于上述的思想,可以很快写出如下代码:

public int binarySearch(int[] a,int key) {int low = 0;int high = a.length - 1;int mid = 0;while(low <= high){mid = (low + high) / 2;if(a[mid] == key) return mid;if(a[mid] > key) high = mid - 1;if(a[mid] < key) low = mid + 1;}return -1;}

实际上,二分查找的过程可以绘制成一棵二叉树,每次二分查找的过程就相当于把原来的树划分为两棵子树,所以每次二分之后下次就只需要查找其中一半的数据就可以了。那么二分查找算法的时间复杂度是多少呢?在最好的情况下,只需要查找一次就可以了,因为这时候中间记录的关键字与要查找的key是相等,自然一次就够了。在最坏的情况下是从根节点查找到最下面的叶子结点,这个过程需要的时间复杂度是O(logn)。

需要注意的是,虽然二分查找算法的效率很高(这也是二分查找算法被广泛应用的原因),但是仍然是有使用条件的:有序。就是说在需要频繁进行插入或者删除操作的数据记录中使用二分查找算法不太划算,因为要维持数据的有序还需要额外的排序开销。

二分查找算法的变种一:插值查找算法

可以发现二分查找每次都是选取中间的那个记录关键字作为划分依据的,那为什么不可以是其他位置的关键字呢?在有些情况下,使用二分查找算法并不是最合适的。举个例子:在1-1000中,一共有1000个关键字,如果要查找关键字10,按照二分查找算法,需要从500开始划分,这样的话效率就比较低了,所以有人提出了插值查找算法。说白了就是改变划分的比例,比如三分或者四分。

插值查找算法对二分查找算法的改进主要体现在mid的计算上,其计算公式如下:

mid=low+key−a[low]a[high]−key(high−low)

而原来的二分查找公式是这样的:

mid=low+12(high−low)

所以我们发现主要变化的地方是12这个系数。其思想可以总结如下:插值查找是根据要查找的关键字的key与查找表中最大最小记录的关键字比较之后的查找算法,其核心是上述计算mid的计算公式。由于大体框架与二分查找算法是一致的,所以时间复杂度仍然是O(logn)。

二分查找算法变种二:斐波那契查找算法

从前面的分析中可以看到,无论划分的关键字太大或者太小都不合适,所以又有人提出了斐波那契查找算法,其利用了黄金分割比原理来实现的。

一个数列如果满足F(n)=F(n-1)+F(n-2),则称这个数列为斐波那契数列。在斐波那契查找算法中计算mid的公式如下:

mid=low+F(k−1)−1

其实现代码如下:

package com.rhwayfun.algorithm.search;public class FibonacciSearch {public int fibonacciSearch(int[] a,int key){int low = 0,high = a.length - 1,mid = 0,k = 0,i =0;//计算数组的长度的值在斐波那契数列的位置while(a.length > F(k) - 1){k++;}//将不满的数值补全int[] newArray = new int[F(k) - 1];System.arraycopy(a, 0, newArray, 0, a.length);for(i = a.length; i < F(k) - 1; i++)newArray[i] = a[a.length - 1];a = newArray;//查找过程while(low <= high){mid = low + F(k-1) - 1;if(key < a[mid]){high = mid - 1;k = k - 1;}else if(key > a[mid]){low = mid + 1;k = k - 2;}else{if(mid < a.length){return mid;}else{//说明是补全之后的数值return a.length - 1;}}}return 0;}//返回第n项斐波那契数列的值private int F(int n) {if(n == 0){return 0;}else if(n == 1){return 1;}int one = 1;int two = 0;int sum = 0;for (int i = 2; i <= n; i++) {sum = one + two;two = one;one = sum;}return sum;}public static void main(String[] args) {int[] a = {0,1,16,24,35,47,59,62,73,88,99};int i = new FibonacciSearch().fibonacciSearch(a, 59);System.out.println(a[i]);}
}

可以看出斐波那契查找算法的核心是如果要查找的记录在右侧,则左边就不会再去查找了,不断反复进行下去,知道查找成功。虽然斐波那契查找算法的时间复杂度也是O(logn),但是从性能看,仍然是优于二分查找算法的。

二分查找算法及其变种相关推荐

  1. 二分查找算法详解(经典二分和左右边界查找)

    目录 二分查找算法 1. 二分查找算法框架 2. 经典二分查找算法 问题1. 为什么while循环中使用<=号而不是用<号,右边区间right为什么要对数组大小减一? 问题2. 为什么 l ...

  2. 二分查找算法的一点改进

    在计算机科学中,二分查找,是一种在有序数组中查找某一特定元素的搜索算法.这种搜索算法每一次比较都使搜索范围减半.第一篇二分查找的论文发表于1946年,然而第一个没有bug的二分查找算法却是在1962年 ...

  3. 二分查找算法的两种实现方式:非递归实现和递归实现

    二分查找的条件是对一组有序数组的查找,这一点很容易忘记,在使用二分查找的时候先要对数组进行排序. 先说一下二分查找的思路:一个有序数组,想要查找一个数字key的下标,首先算出中间下标mid,利用mid ...

  4. 二分查找算法为什么要先排序

    其实二分查找算法就和我们在一个英文字典中找一个单词一样,比如要找middle这个单词,先把字典翻到大概中间的位置,那么现在字典就被分成两个部分了,middle这个单词要么在第一个部分,要么在第二个部分 ...

  5. LeetCode面试刷题技巧-二分查找算法代码思路解析

    二分查找的思想 提及二分查找算法,我想大部分人都不陌生,就算不是学计算机的,基本上也都使用过二分查找的思想,不信的话,且听我慢慢为你道来. 不知道你有没有玩过这样一个游戏,猜数字.就是说一个人心里想了 ...

  6. Python 二分查找算法

    如果有这样一个列表,让你从这个列表中找到66的位置,你要怎么做? l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76 ...

  7. 二分查找算法(递归与非递归两种方式)

    首先说说二分查找法. 二分查找法是对一组有序的数字中进行查找,传递相应的数据,进行比较查找到与原数据相同的数据,查找到了返回1,失败返回对应的数组下标. 采用非递归方式完成二分查找法.java代码如下 ...

  8. JavaScript实现binarySearch二分查找算法(附完整源码)

    JavaScript实现binarySearch二分查找算法(附完整源码) Comparator.js完整源代码 binarySearch.js完整源代码 binarySearch.test.js完整 ...

  9. 顺序查找与二分查找算法

    顺序查找算法 顺序查找是非常简单常用的查找算法,基本思路:从第一个元素m开始逐个与需要查找的元素x进行比较,当比较到元素值相同(即m=x)时返回元素m的下标,如果比较到最后都没有找到,则返回-1.该算 ...

最新文章

  1. 转贴: OpenGL开发库的组成
  2. python编写直角三角形边长公式_304不锈钢的重量计算公式,留着总有用处
  3. C++判断文件是否存在
  4. po 价格条件表_SAP-MM定价条件全解析 -
  5. [译]用AngularJS构建大型ASP.NET单页应用(二)
  6. 高性能并发TCP网络服务-IOCP框架修正VC2008版本
  7. Windows中常用的函数调用规范
  8. 深入分析Nginx 502 Bad Gateway和Nginx 504 Gateway Time-out
  9. Python内置函数之-struct
  10. 圣思园【深入JVM】笔记-第一课-论学习方法
  11. Mac怎么安装Andriod模拟器
  12. ESP8266+blinker测温湿度
  13. xbox会员中心在哪_白金会会员中心
  14. python逗号表达式_正则表达式 - 在第一个逗号前获取所有内容。 - python
  15. HIS(医院信息系统HospitalInformationSystem)
  16. 4.12 使用格式刷实现单元格样式的快速复制 [原创Excel教程]
  17. 淘宝/天猫平台商品详情API接口调用说明
  18. Build file: no target in no project
  19. 2022-2028全球与中国混合云数据仓库服务市场现状及未来发展趋势
  20. 简单的S40后台运行

热门文章

  1. Boost:计时系的测试
  2. ITK:追加两个3D体积
  3. ITK:用常量填充图像
  4. DCMTK:Irradiation事件识别测试FG类
  5. C语言创建map,遍历map
  6. QT的QGLFormat类的使用
  7. c++运算符和结合性
  8. 该功能仅支持Android5.0,Android 5.0 android:elevation适用于View,但不适用于Button?
  9. 模型训练速度过慢,GPU利用率低
  10. kerberos安装配置、配置kerberos server、client、日常操作与常见问题、卸载kerberos、hive整合kerberos