查找算法之二分查找(对半查找)
当有序表采用顺序存储时,可以采用二分查找的方式查找指定关键字的元素。
二分查找的基本思想是选择表中某一位置 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=1ki∗2i−1=n1∑i=1ki∗(2i−2i−1)lb(n+1)+nlb(n+1)−1lb(n+1)(当n较大时)
因此,在有序表中成功查找一个元素,对半查找的平均搜索长度为 O ( l b n ) O(lbn) O(lbn)。但是需要注意的是,这棵树在查找过程中并没有实际建立,这只是为了便于分析而建的分析模型。
本篇完
查找算法之二分查找(对半查找)相关推荐
- 查找算法:二分查找、顺序查找
08年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大学生活.此系列是对四年专业课程学习的回顾,索引参见:http://blog.csdn.net/xiaowei_cqu/article/de ...
- 【数据结构与算法】插值查找算法、斐波那契查找算法(黄金分割法)的介绍和程序实现
目录 1. 插值查找算法 1.1 插值查找算法的介绍 1.2 插值查找算法的程序实现 2. 斐波那契查找算法 2.1 斐波那契查找算法的介绍 2.2 斐波那契查找算法的程序实现 1. 插值查找算法 1 ...
- 查找算法【二叉查找树】 - 二叉查找树的查找
查找算法[二叉查找树] - 二叉查找树的查找 因为二叉查找树的中序遍历有序性,所以查找与二分查找类似,每次都缩小查找范围,查找效率较高. [算法步骤] ① 若二叉查找树为空,查找失败,则返回空指针. ...
- 查找算法:斐波那契查找算法实现及分析
斐波那契查找算法介绍 斐波那契查找法肯定与斐波那契相关嘛,斐波那契数列 又称黄金分割数列.所以我们先把黄金分割弄懂,后面代码才能看得懂!黄金分割点大家都知道吧.1:0.618或者1.618:1,我们的 ...
- C++实现查找 - 顺序、二分和哈希查找
数据结构与算法专栏 -- C++实现 写在前面: 前面我们其实已经涉及到了查找算法,比如二叉排序树和平衡二叉树等.这一讲我们来补充一下其它常见的查找算法,下面我会依次讲解并实现顺序查找.二分查找和哈希 ...
- 查找算法之斐波那契查找算法
斐波那契(黄金分割法)查找算法 (一)算法简介 (1)斐波那契数列 在讲算法之前,我们先介绍一下斐波那契数列,该数列公式为F(K) = F(k-1) + F(k-2),即 1.1.2.3.5.8.13 ...
- python二分法查找算法_顺序查找算法和折半(二分法)查找算法,C语言查找算法详解...
查找是指在大量的信息中寻找一个特定的信息.在计算机中,查找是非常重要的一个应用,比如"百度".查找算法的好坏直接影响查找的速度. 常用的查找算法主要有顺序查找和折半(二分法)查找: ...
- c语言顺序查找算法,c语言实现排序和查找所有算法
c语言版排序查找完成,带详细解释,一下看到爽,能直接运行看效果. /* Note:Your choice is C IDE */ #include "stdio.h" #inclu ...
- 【查找算法】6种常见的查找算法简述及Python代码实现
我是一个甜甜的大橙子
最新文章
- bootstrap怎么用_不用自己写css,不用bootstrap,写样式有tailwindcss就足够了
- linux 匹配文本中的ip,linux文本三剑客匹配网卡IP地址大PK(CentOS 7系统)
- 专栏-美国人口和都市区
- oracle 如何数组变成表,Oracle从零开始19——表的管理09——嵌套表和可变数组
- 免费网络学术资源获取
- 【线上分享】华为云视频的Cloud Native实践
- MySQL 读写分离 使用驱动com.mysql.jdbc.ReplicationDriver
- 计算机资格考试中级工程师种类,中级工程师职称考试类别及注意事项
- shell中的正则表达式
- SpringCloud Alibaba - Nacos 作为配置中心 读取Properties配置信息
- 控制台应用程序转成MFC程序错误—OcrRec.exe触发一个触点,原因可能是堆被破坏
- 项目搭建 windows_08. SpringCloud实战项目-配置Git
- centos7设置键盘类型_CentOS7设置中文输入法
- Altium Designed导出Gerber,Gerber文件所对应的层
- linux命令大全密码修改,linux修改密码命令
- NMF扩展名是什么文件
- springboot 调用萤石Saas平台
- 如何区分杠精和批判性思维
- MacOS安装git
- 尺寸公DTAS差分析尺寸链计算软件:DTAS3D在车身公差分析中的应用案例
热门文章
- 产品生命周期专业术语积累
- 示例 在 ABAP 中使用自己的 RSA 实现 RSA Encryption in ABAP
- element 走马灯实现图片轮播
- 如何用计算机把数字12变成21,2015年12月计算机二级office考试题及答案
- SynchroTrap-基于松散行为相似度的欺诈账户检测算法
- 【电机/控制理论】DTC(Direct Torque Control)直接转矩控制
- selenium 模拟登录 突破图片验证码(豆瓣网)
- 第26届中学生计算机大赛,南京中学生自编APP获全国高校计算机大赛一等奖
- VMware Horizon View 7 规划部署图解
- 两步路轨迹文件位置_两步路户外助手新手使用指南