【PHP数据结构】线性查找与二分查找
欢迎来到查找的世界,在学习完各种数据结构之后,总算走到了这一步,不知道大家有什么感想呢?反正我是边学边忘,现在让我去说说图的那几个算法还是在蒙圈的状态中。不过学习嘛,就是一步一步的来,暂时搞不懂的东西其实也是可以放一放的。打破砂锅和坚持不懈当然是好的品德,但有些东西可能真的是需要时间去消化的,甚至可能是需要真实的项目经历才能彻底搞明白。在我们编程行业来说就是典型的这种实践的学习形式效果会更好,很多人在上大学的时候对于数据结构以及其它专业课都是以死记硬背为主,包括上了多少年班的同学可能都没有在业务代码中真正的使用过什么算法,所以理解它们确实是非常困难的。这时,我们可以暂时休息一下,转换一下思路,学习最主要的就是预习和复习,在这次学习完之后,将来再进行多次的复习,研究各种不同的资料,迟早有一天大家都能搞明白的。
今天的内容其实就非常简单了,可以说是除了线性表之外最简单的内容。我们只研究两个非常初级的查找,那就是顺序查找和折半查找。相信不少同学可能早就会了,一般培训机构讲数据结构和算法时,查找必讲二分,排序必讲冒泡,更不用说正规大学对口专业出身的同学了。当然,这两个也是非常简单的,不管你有没有基础,咱们一起来看看吧。
不管你是什么算法题,还是在实际的业务开发中,查找都是非常重要的,甚至可能比排序还要重要。想想你整天面向数据库编程是在干嘛?不就是 CRUD 嘛,其中大部的业务还都是以搜索查找居多,我们在优化数据库时,也主要是优化各种查询语句。当然,要说到数据库的查找那就太高深了,以后我们学习 MySQL 相关的知识时再详细讲解,特别是索引中的 B+ 树,就是数据结构和算法的核心思想的体现。好吧,不吹牛了,也不敢在这里多说了,因为自己也没研究透呢。
线性查找(顺序查找)
顾名思义,不管是叫线性还是叫顺序,很明显,就是一条数据一条数据的对比下去就好啦。
function SearchSeq($sk, $arr)
{
for ($i = 0; $i < count($arr); $i++) {
if ($sk == $arr[$i]) {
echo $i, PHP_EOL;
break;
}
}
echo "线性查找次数:" . $i, PHP_EOL;
}
嗯,真的是连解释都不想解释了,这段代码要是看不懂的话就先去复习下基本的循环和条件判断语句吧!很明显,一次线性查找的时间复杂度就是 O(N) 。
二分查找(折半查找)
既然都这么简单,那么我们再直接给出折半查找的代码。
function SearchBin($sk, $arr){
$left = 0;
$right = count($arr) - 1;
$i = 0;
while ($left <= $right) {
$i++;
$mid = (int) (($left + $right) / 2);
if ($arr[$mid] > $sk) {
$right = $mid - 1;
} else if ($arr[$mid] < $sk) {
$left = $mid + 1;
} else {
echo $mid, PHP_EOL;
break;
}
}
echo "折半查找次数:" . $i, PHP_EOL;
}
折半查找的前提是数据必须是有序的,这样我们就可以根据数据问题的长度来获取中间的数,然后跟要对比的数进行比较,如果小于这个数,就在前一半数据中查找,如果大于这个数,就在后一半部分中进行查找。一会看例子再详细说明。
对比
两个算法其实都很简单,我们直接看看他们的运行情况和效率区别。
$arr = [5, 6, 19, 25, 4, 33, 56, 77, 82, 81, 64, 37, 91, 23];
// 输入 56
fscanf(STDIN, "%d", $searchKey);
SearchSeq($searchKey, $arr);
// 6
// 线性查找次数:6
sort($arr);
print_r($arr);
SearchBin($searchKey, $arr);
// 8
// 折半查找次数:3
首先我们定义了一个数组,其实就是随便给了一些数据。然后输入一个数据,查找它在数组中的位置。比如我们在测试代码中输入了 56 ,线性查找是循环进行了 6 次,找到 56 所在的位置为下标 6 的位置。
对于折半查找来说,我们需要先给数组排序,这时 56 会排在下标为 8 的位置,而在折半查找的循环中,我们只循环了 3 次就找到了这个位置。是不是感觉快了很多,一下就快了一倍。这可不是它的真正实力哦,折半查找的真实实力是 对数 级别的效率,也就是它的时间复杂度为 O(logN) 。我们先来结合上面的代码看下它这三次循环都干了什么。
第一次进入,mid 为 6 (0+13=13,除2),下标为 arr[6] 的值为 3 ,比 56 小,所以 left = 6+1 = 7
第二轮循环,mid 为 10(7+13=20,除2),下标为 arr[10] 的值为 77 ,比 56 大,所以 right = 10-1 = 9
第三轮循环,mid 为 9(7+9=16,除2),下标为 arr[8] 的值为 56,结束
其实很多猜数字的游戏也都是这么玩的,比如给你一个范围,0-100的数,猜他写下的是哪个数,最快最简单的方法也就是这种折半查找的方式,我们只需要最多 7 次就可以猜出 100 以内的数。很明显,这就是对数的威力。下面我们再来看一个更直观的,十万个有序的数,我们就找最后那一个数,看看顺序查找和折半查找能有多大差距。
$arr = range(1, 100000);
$searchKey = 100000;
SearchSeq($searchKey, $arr);
// 99999
// 线性查找次数:99999
SearchBin($searchKey, $arr);
// 99999
// 折半查找次数:17
嗨不嗨,这就是对数的威力!!我们需要 2 的 7 次方才能覆盖 100 以内的数,但我们只需要 2 的 17 次方,就能覆盖十万以内的数,这个效率差距还是随着 N 的越来越大而越来越明显的。
总结
今天的内容是不是很简单,虽说内容简单,但是我们却见识到了不同算法效率之间的巨大差异。当然,折半查找也有其本身的局限,那就是数据必须是的序的,当然,在合适的情况下我们也可以选用一个 O(logN) 的排序算法,这样总体的时间复杂度就还能保持在对数级别了。总之,先掌握好这些简单的内容,千万别在面试的时候连这一关都过不了哦!
测试代码:
参考文档:
《数据结构》第二版,严蔚敏
《数据结构》第二版,陈越
《数据结构高分笔记》2020版,天勤考研
关注公众号:【硬核项目经理】获取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料
知乎、公众号、抖音、头条搜索【硬核项目经理】
B站ID:482780532
【PHP数据结构】线性查找与二分查找的更多相关文章
- List<T>线性查找和二分查找BinarySearch效率分析
今天因为要用到List的查找功能,所以写了一段测试代码,测试线性查找和二分查找的性能差距,以决定选择哪种查找方式. 线性查找:Contains,Find,IndexOf都是线性查找. 二分查找:Bin ...
- C语言查找算法之顺序查找、二分查找(折半查找)
C语言查找算法之顺序查找.二分查找(折半查找),最近考试要用到,网上也有很多例子,我觉得还是自己写的看得懂一些. 顺序查找 /*顺序查找 顺序查找是在一个已知无(或有序)序队列中找出与给定关键字相同的 ...
- 各种查找算法的选用分析(顺序查找、二分查找、二叉平衡树、B树、红黑树、B+树)
目录 顺序查找 二分查找 二叉平衡树 B树 红黑树 B+树 参考文档 顺序查找 给你一组数,最自然的效率最低的查找算法是顺序查找--从头到尾挨个挨个遍历查找,它的时间复杂度为O(n). 二分查找 而另 ...
- Java中常用的查找算法——顺序查找和二分查找
Java中常用的查找算法——顺序查找和二分查找 神话丿小王子的博客 一.顺序查找: a) 原理:顺序查找就是按顺序从头到尾依次往下查找,找到数据,则提前结束查找,找不到便一直查找下去,直到数据最后一位 ...
- Java基础知识强化60:经典查找之二分查找
1. 二分查找 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好:其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表. 比较 ...
- Java顺序查找、二分查找
Java顺序查找.二分查找 查找算法中顺序查找算是最简单的了,无论是有序的还是无序的都可以,只需要一个个对比即可,但其实效率很低. 顺序查找 动图演示 详细代码 // 顺序查找 public st ...
- 数组查找算法的C语言 实现-----线性查找和二分查找
线性查找 Linear Search 用户输入学生学号的成绩 二分查找 Binary Search 要求数据表是已经排好序的 程序存在小的瑕疵
- php查找之二分查找
二分查找,往往是针对有序的数组进行查找,我们假设一个序列是数组有序,然后给定一个数字,查出它应该在这个数组中的排序位置 百度百科中讲到 二分查找也称折半查找(Binary Search),它是一种效率 ...
- jvascript 顺序查找和二分查找法
第一种:顺序查找法 中心思想:和数组中的值逐个比对! /* * 参数说明: * array:传入数组 * findVal:传入需要查找的数 */ function Orderseach(array,f ...
随机推荐
- 常见web中间件漏洞(四)Tomcat漏洞
这部分好久没写了,继续更新web中间件漏洞思路整理(不复现) ,争取...整理完 前几篇指路链接: nginx: https://www.cnblogs.com/lcxblogs/p/13596239 ...
- Spring中为什么不建议使用字段注入
在使用Idea中通过注解注入字段时是否遇见过这样一个提示: Field injection is not recommended(不推荐使用字段注入) 一. 什么是字段注入,Spring中依赖注入的方 ...
- Python成员运算,身份运算和流程控制
成员运算 in #判断--在--里面 print('a' in 'abcd') # 字符串判断a是否在abcd里面 print('you' in 'how are you') # 这种整体也可以判断 ...
- 旅游景点 Tourist Attractions 题解
题面在这里 再次破了纪录,连做了3天... 让我们从头来一点一点分析 1.预处理 先看题面,乍一看貌似是个图论题,有n个点m条边,给定一些必须经过的点和强制经过顺序,求一条最短路 我们发现n和m都比较 ...
- asp.net core 搭建WebAPI微服务-----cosnul服务
参考网址:https://blog.csdn.net/weixin_42084199/article/details/108643555 在此之前需要准备的是: vs2019,以往版本不支持dotne ...
- element ui loading加载开启与关闭
参考:https://blog.csdn.net/qq_41877107/article/details/87690555 Vue项目引入element-ui,之后,将以下代码写入 mounted() ...
- C# Fakes
我们为了测试程序的运行逻辑,需要写单元测试来验证程序的逻辑.有的时候我们的逻辑需要依赖于外界的事物(需要一个文件,eg:数据库),我们不可能在运行单元测试的计算机都创建一个数据库,所以这个时候我们就需 ...
- 集合的打印、列表List、迭代器Iterators
集合的打印 必须使用 Arrays.toString() 来生成数组的可打印形式. 但是打印集合无需任何帮助. /** * 集合的打印 * @author myf */ public class Pr ...
- Seq2Seq sequence-to-sequence模型 简介
Sequence-to-sequence (seq2seq) 模型. 突破了传统的固定大小输入问题框架 开创了将DNN运用于翻译.聊天(问答)这类序列型任务的先河 并且在各主流语言之间的相互翻译,和语 ...
- C# ThreadPool 分批处理数据,所有数据执行完再返回
这是一个调用翻译数据的功能,所有数据一次性提交会造成后台服务压力大,接口反应时间也长. 所以做了一个分批处理,等待所有批次的数据调用接口都返回后再执行下一步. 1 /// <summary> ...