当有序表采用顺序存储时,可以采用二分查找的方式查找指定关键字的元素。
  二分查找的基本思想是选择表中某一位置 i i i的元素 A i A_i Ai​,设该元素的关键字为 K i K_i Ki​,将 K i K_i Ki​与待查找关键字 k e y key key比较。

关键字 K 0 K_0 K0​ K 1 K_1 K1​ K 2 K_2 K2​ K 3 K_3 K3​ K 4 K_4 K4​ …… K i − 1 K_{i-1} Ki−1​ K i K_i Ki​ k i + 1 k_{i+1} ki+1​ …… K n − 4 K_{n-4} Kn−4​ K n − 3 K_{n-3} Kn−3​ K n − 2 K_{n-2} Kn−2​ K n − 1 K_{n-1} Kn−1​ K n K_n Kn​
元素值 A 0 A_0 A0​ A 1 A_1 A1​ A 2 A_2 A2​ A 3 A_3 A3​ A 4 A_4 A4​ …… A i − 1 A_{i-1} Ai−1​ A i A_i Ai​ A i + 1 A_{i+1} Ai+1​ …… A n − 4 A_{n-4} An−4​ A n − 3 A_{n-3} An−3​ A n − 2 A_{n-2} An−2​ A n − 1 A_{n-1} An−1​ A n A_n An​

  比较的结果当然只有三种可能性:

  • k e y key key < K i K_i Ki​:当带查找的关键字存在于有序表中,且该有序表是采用升序方式存储的,那么待查找关键字 k e y key key对应的元素肯定在子表( A 1 A_1 A1​, A 2 A_2 A2​,……, A i − 1 A_{i-1} Ai−1​)中。那么只需在子表中继续按这一规则进行查找便可完成查找。
  • k e y key key = K i K_i Ki​:若待查找的关键字等于 K i K_i Ki​时,则表示查找成功。
  • k e y key key > K i K_i Ki​:当待查关键字大于当前关键字时,则表示待查找关键字对应的元素如果存储在表中,则一定在子表( A i + 1 A_{i+1} Ai+1​, A i + 2 A_{i+2} Ai+2​,……, A n A_n An​)中,按这一规则继续查找该子表。
      那么这个 i i i如何确定呢,根据不同的规则来确定这个 i i i,可以得到不同的二分搜索方法,如对半搜索,斐波那契搜索和插值搜索等。

对半查找

  设查找子表中第一个元素的序号定为 l o w low low,最后一个元素的序号定为 h i g h high high,令 i = ( l o w + h i g h ) / 2 i=(low+high)/2 i=(low+high)/2,这种二分查找称为对半查找。对半查找算法将表划分为几乎相等的两个子表。
  从二分查找的思想中可以看出这种查找方式是一种递归查找,根据这种查找算法思想,可以很容易写出对半查找的递归算法:

typedef struct
{int key;int value;
}s_eletype;typedef struct
{int size;s_eletype* element;
}s_list;int _search(s_list lst, int k, int low, int high)
{int mid;if (low <= high){mid = (low + high) / 2;if (k < lst.element[mid].key) return _search(lst, k, low, mid - 1);else if (k > lst.element[mid].key) return _search(lst, k, mid + 1, high);else return mid;}return -1;
}int search(s_list lst, int k, s_eletype* x)
{int i = _search(lst, k, 0, lst.size - 1);if (i != -1){*x = lst.element[i];return true;}else return false;}

  递归算法效率往往比较低,在递归中过程中,需要不断调用递归函数本身,对栈开销比较大,调用过程中压栈和返回同样也需要花费大量时间。因此递归函数在能够转换成迭代算法时,一般采用迭代的方式进行运算。
  将_search函数以迭代的方式实现:

int _search(s_list lst, int k, int low, int high)
{int mid;while (low <= high){mid = (low + high) / 2;if (k < lst.element[mid].key) high = mid - 1;else if (k > lst.element[mid].key) low = mid + 1;else return mid;}return -1;
}

  对半查找只适用于顺序存储的有序表,在运行过程中需要不断的计算子表的 m i d mid mid序号,这对于链式存储来说无法实现。

二叉判定树

  如果将有序数据构建成一颗平衡因子只有0-1的的二叉搜索平衡树,那么对半查找过程会变成什么样呢?以下列数据为例:

i 0 1 2 3 4 5 6 7 8 9
key 21 30 36 41 52 54 66 72 83 97

  如果要查找 k e y key key为66的元素,对半查找的过程如下:

序号 0 1 2 3 4 5 6 7 8 9
第一次 21 30 36 41 52 54 66 72 83 97
第二次 21 30 36 41 52 54 66 72 83 97
第三次 21 30 36 41 52 54 66 72 83 97
第四次 21 30 36 41 52 54 66 72 83 97

  蓝色和绿色关键字表示该次查找的子表范围,绿色表示该次查找时与待查找关键字比较的关键字。
  这是查找成功的情况,那么查找失败的情况呢?例如要查找 k e y key key为67的元素,很显然过程跟上面的过程一样,只是在第最后一次查找的时候仍然没有找到匹配的关键字,程序会继续执行一次,如果是迭代算法,那么low = mid+1,此时条件已经不满足while,程序返回-1
  将这些数据建成一颗平衡因子只有0-1的的二叉搜索平衡树,那颗树会长什么样?

  在这颗二叉搜索树上进行查找 k e y key key值为66的元素过程是怎么样的?

  这颗二叉搜索树的查找路径不就是对半查找的查找过程吗?那对半查找的性能分析就可以在这颗树的基础上进行了。
  一颗有n个节点的二叉判定树的高度为[lbn]+1(本篇中:[lbn]表示向下取整,{lbn}表示向上取整)。所以对半查找在查找成功的情况下,关键字值之间的比较次数不超过[lbn]+1;对于不成功的查找,需要进行[lbn][lbn]+1次比较。
  为了讨论简单,假定表的长度为 2 k − 1 2^k-1 2k−1,即构成的二叉判定树为一颗满二叉树,二叉树的高度为 k k k=lb(n+1)根据二叉树的性质,在每个元素的查找概率相等时,可以求得查找成功是的平均搜索长度为
A S L s = 1 n ∑ i = 1 k i ∗ 2 i − 1 = 1 n ∑ i = 1 k i ∗ ( 2 i − 2 i − 1 ) = l b ( n + 1 ) + l b ( n + 1 ) n − 1 ⩽ l b ( n + 1 ) ( 当 n 较 大 时 ) \begin{array}{rcl}ASL_s\;&=&\;\frac1n\sum_{i=1}^ki\ast2^{i-1}=\frac1n\sum_{i=1}^ki\ast(2^i-2^{i-1})\\&\\&=&lb(n+1)+\frac{lb(n+1)}n-1\\&\\&\leqslant&lb(n+1)\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;(当n\mathrm{较大时})\end{array} ASLs​​==⩽​n1​∑i=1k​i∗2i−1=n1​∑i=1k​i∗(2i−2i−1)lb(n+1)+nlb(n+1)​−1lb(n+1)(当n较大时)​
  因此,在有序表中成功查找一个元素,对半查找的平均搜索长度为 O ( l b n ) O(lbn) O(lbn)。但是需要注意的是,这棵树在查找过程中并没有实际建立,这只是为了便于分析而建的分析模型。

本篇完

查找算法之二分查找(对半查找)相关推荐

  1. 查找算法:二分查找、顺序查找

    08年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大学生活.此系列是对四年专业课程学习的回顾,索引参见:http://blog.csdn.net/xiaowei_cqu/article/de ...

  2. 【数据结构与算法】插值查找算法、斐波那契查找算法(黄金分割法)的介绍和程序实现

    目录 1. 插值查找算法 1.1 插值查找算法的介绍 1.2 插值查找算法的程序实现 2. 斐波那契查找算法 2.1 斐波那契查找算法的介绍 2.2 斐波那契查找算法的程序实现 1. 插值查找算法 1 ...

  3. 查找算法【二叉查找树】 - 二叉查找树的查找

    查找算法[二叉查找树] - 二叉查找树的查找 因为二叉查找树的中序遍历有序性,所以查找与二分查找类似,每次都缩小查找范围,查找效率较高. [算法步骤] ① 若二叉查找树为空,查找失败,则返回空指针. ...

  4. 查找算法:斐波那契查找算法实现及分析

    斐波那契查找算法介绍 斐波那契查找法肯定与斐波那契相关嘛,斐波那契数列 又称黄金分割数列.所以我们先把黄金分割弄懂,后面代码才能看得懂!黄金分割点大家都知道吧.1:0.618或者1.618:1,我们的 ...

  5. C++实现查找 - 顺序、二分和哈希查找

    数据结构与算法专栏 -- C++实现 写在前面: 前面我们其实已经涉及到了查找算法,比如二叉排序树和平衡二叉树等.这一讲我们来补充一下其它常见的查找算法,下面我会依次讲解并实现顺序查找.二分查找和哈希 ...

  6. 查找算法之斐波那契查找算法

    斐波那契(黄金分割法)查找算法 (一)算法简介 (1)斐波那契数列 在讲算法之前,我们先介绍一下斐波那契数列,该数列公式为F(K) = F(k-1) + F(k-2),即 1.1.2.3.5.8.13 ...

  7. python二分法查找算法_顺序查找算法和折半(二分法)查找算法,C语言查找算法详解...

    查找是指在大量的信息中寻找一个特定的信息.在计算机中,查找是非常重要的一个应用,比如"百度".查找算法的好坏直接影响查找的速度. 常用的查找算法主要有顺序查找和折半(二分法)查找: ...

  8. c语言顺序查找算法,c语言实现排序和查找所有算法

    c语言版排序查找完成,带详细解释,一下看到爽,能直接运行看效果. /* Note:Your choice is C IDE */ #include "stdio.h" #inclu ...

  9. 【查找算法】6种常见的查找算法简述及Python代码实现

    我是一个甜甜的大橙子

最新文章

  1. bootstrap怎么用_不用自己写css,不用bootstrap,写样式有tailwindcss就足够了
  2. linux 匹配文本中的ip,linux文本三剑客匹配网卡IP地址大PK(CentOS 7系统)
  3. 专栏-美国人口和都市区
  4. oracle 如何数组变成表,Oracle从零开始19——表的管理09——嵌套表和可变数组
  5. 免费网络学术资源获取
  6. 【线上分享】华为云视频的Cloud Native实践
  7. MySQL 读写分离 使用驱动com.mysql.jdbc.ReplicationDriver
  8. 计算机资格考试中级工程师种类,中级工程师职称考试类别及注意事项
  9. shell中的正则表达式
  10. SpringCloud Alibaba - Nacos 作为配置中心 读取Properties配置信息
  11. 控制台应用程序转成MFC程序错误—OcrRec.exe触发一个触点,原因可能是堆被破坏
  12. 项目搭建 windows_08. SpringCloud实战项目-配置Git
  13. centos7设置键盘类型_CentOS7设置中文输入法
  14. Altium Designed导出Gerber,Gerber文件所对应的层
  15. linux命令大全密码修改,linux修改密码命令
  16. NMF扩展名是什么文件
  17. springboot 调用萤石Saas平台
  18. 如何区分杠精和批判性思维
  19. MacOS安装git
  20. 尺寸公DTAS差分析尺寸链计算软件:DTAS3D在车身公差分析中的应用案例

热门文章

  1. 产品生命周期专业术语积累
  2. 示例 在 ABAP 中使用自己的 RSA 实现 RSA Encryption in ABAP
  3. element 走马灯实现图片轮播
  4. 如何用计算机把数字12变成21,2015年12月计算机二级office考试题及答案
  5. SynchroTrap-基于松散行为相似度的欺诈账户检测算法
  6. 【电机/控制理论】DTC(Direct Torque Control)直接转矩控制
  7. selenium 模拟登录 突破图片验证码(豆瓣网)
  8. 第26届中学生计算机大赛,南京中学生自编APP获全国高校计算机大赛一等奖
  9. VMware Horizon View 7 规划部署图解
  10. 两步路轨迹文件位置_两步路户外助手新手使用指南