PHP有序表查找之插值查找算法示例


Posted in PHP onFebruary 10, 2018

本文实例讲述了PHP有序表查找之插值查找算法。分享给大家供大家参考,具体如下:

前言:

在前面我们介绍了二分查找,但是我们考虑一下,为什么一定要折半呢?而不是折四分之一或者更多?

打个比方,在英文词典里查找“apple”,你下意识里翻开词典是翻前面的书页还是后面的书页呢?如果再查“zoo”,你又会怎么查?显然你不会从词典中间开始查起,而是有一定目的地往前或往后翻。

同样,比如要在取值范围在 0 ~ 10000 之间的100个元素从小到大均匀分布的数组中查找5,我们自然而然地先考虑数组下标较小的开始查找。

以上的分析其实就是插值查找的思想,它是二分查找的改进。

基本思想:

根据要查找的关键字key与查找表中的最大最小记录的关键字比较后的查找方法,其核心就在于插值计算公式,我们先看折半查找的计算公式:

 PHP有序表查找之插值查找算法示例

而插值查找就是要将其中的 1/2进行改进,改成下面的计算方案:

 PHP有序表查找之插值查找算法示例

插值查找算法的核心就在于插值的计算公式:

$num - $arr[$lower]
—————————————
$arr[$high] - $arr[$lower]

代码:

<?php
//插值查找(前提是数组必须是有序数组) 事件复杂度 O(logn)
//但对于数组长度比较大,关键字分布又是比较均匀的来说,插值查找的效率比折半查找的效率高
$i = 0; //存储对比的次数
//@param 待查找数组
//@param 待搜索的数字
function insertsearch($arr,$num){
 $count = count($arr);
 $lower = 0;
 $high = $count - 1;
 global $i;
 while($lower <= $high){
  $i ++; //计数器
  if($arr[$lower] == $num){
   return $lower;
  }
  if($arr[$high] == $num){
   return $high;
  }
  // 折半查找 : $middle = intval(($lower + $high) / 2);
  $middle = intval($lower + ($num - $arr[$lower]) / ($arr[$high] - $arr[$lower]) * ($high - $lower)); 
  if($num < $arr[$middle]){
   $high = $middle - 1;
  }else if($num > $arr[$middle]){
   $lower = $middle + 1;
  }else{
   return $middle;
  }
 }
 return -1;
}
$arr = array(0,1,16,24,35,47,59,62,73,88,99);
$pos = insertsearch($arr,62);
print($pos);
echo "<br>";
echo $i;

总结:

从时间复杂度上来看,它也是 O(logn),但对于有序表比较长,而关键字分布有比较均匀的查找表来说,插值查找算法的平均性能比二分查找好的多。反之,数组中如果分布类似于{0,1,2,2000,2001,。。。999998,999999}这种极端不均匀的数据,用插值查找未必是很合适的选择。

我自己特别做了个例子:

$arr = array(0,1,2,2000,2001,2002,2003,2004,5555,69666,99999,100000);
echo "位置:".binsearch($arr,5555);
echo "<br>";
echo "比较次数:".$i;
$i = 0; //重置比较次数
echo "<br>";
echo "位置:".insertsearch($arr,5555);
echo "<br>";
echo "比较次数:".$i;

结果输出:

位置:8
比较次数:2
位置:8
比较次数:9

可以得到,对于极端不均匀的数据,插值查找效率比折半查找低。

PS:上面提到的binsearch()函数大家可以参考前面一篇 PHP有序表查找—-二分查找(折半)

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP超级全局变量数组小结
Oct 04 PHP
php-fpm配置详解
Feb 12 PHP
PHP计算日期相差天数实例分析
Feb 23 PHP
php集成动态口令认证
Jul 21 PHP
PHP接收App端发送文件流的方法
Sep 23 PHP
PHP文件上传处理案例分析
Oct 15 PHP
ecshop适应在PHP7的修改方法解决报错的实现
Nov 01 PHP
PHP实现的Redis多库选择功能单例类
Jul 27 PHP
利用PHPStorm如何开发Laravel应用详解
Aug 30 PHP
浅析PHP7 的垃圾回收机制
Sep 06 PHP
浅谈Laravel中使用Slack进行异常通知
May 29 PHP
PHP 时间处理类Carbon
May 20 PHP
PHP有序表查找之二分查找(折半查找)算法示例
Feb 09 #PHP
php在windows环境下获得cpu内存实时使用率(推荐)
Feb 08 #PHP
PHP基于redis计数器类定义与用法示例
Feb 08 #PHP
php处理抢购类功能的高并发请求
Feb 08 #PHP
php+redis实现商城秒杀功能
Nov 19 #PHP
php+redis消息队列实现抢购功能
Feb 08 #PHP
PHP多线程模拟实现秒杀抢单
Feb 07 #PHP
You might like
咖啡界又出新概念,无需咖啡豆的分子咖啡
2021/03/03 咖啡文化
深入php数据采集的详解
2013/06/02 PHP
golang与PHP输出excel示例
2016/07/22 PHP
模仿jQuery each函数的链式调用
2009/07/22 Javascript
JS 数字转换研究总结
2013/12/26 Javascript
jquery解决客户端跨域访问问题
2015/01/06 Javascript
JavaScript判断浏览器类型的方法
2015/02/10 Javascript
利用jQuery插件imgAreaSelect实现图片上传裁剪(放大缩小)
2016/12/02 Javascript
微信小程序开发的四十个技术窍门总结(推荐)
2017/01/23 Javascript
微信小程序实现图片轮播及文件上传
2017/04/07 Javascript
微信小程序实战之自定义模态弹窗(8)
2017/04/18 Javascript
jQuery常见面试题之DOM操作详析
2017/07/05 jQuery
vue.js数据绑定的方法(单向、双向和一次性绑定)
2017/07/13 Javascript
JS实现数组简单去重及数组根据对象中的元素去重操作示例
2018/01/05 Javascript
vue2和vue3的v-if与v-for优先级对比学习
2020/10/10 Javascript
[46:38]完美世界DOTA2联赛PWL S2 Magma vs PXG 第三场 11.28
2020/12/02 DOTA
Python库urllib与urllib2主要区别分析
2014/07/13 Python
Python压缩解压缩zip文件及破解zip文件密码的方法
2015/11/04 Python
详解Python中的__getitem__方法与slice对象的切片操作
2016/06/27 Python
Python实现选择排序
2017/06/04 Python
修复 Django migration 时遇到的问题解决
2018/06/14 Python
python创建文件备份的脚本
2018/09/11 Python
详解python如何在django中为用户模型添加自定义权限
2018/10/15 Python
Python魔法方法详解
2019/02/13 Python
VSCode Python开发环境配置的详细步骤
2019/02/22 Python
python requests模拟登陆github的实现方法
2019/12/26 Python
详解CSS3阴影 box-shadow的使用和技巧总结
2016/12/03 HTML / CSS
北美三大旅游网站之一:Travelocity加拿大
2016/08/20 全球购物
联强国际笔试题面试题
2013/07/10 面试题
青春奉献演讲稿
2014/05/08 职场文书
军训拉歌口号
2014/06/13 职场文书
股指期货心得体会
2014/09/10 职场文书
医院护士工作检讨书
2014/10/26 职场文书
pytorch中的torch.nn.Conv2d()函数图文详解
2022/02/28 Python
分享7个 Python 实战项目练习
2022/03/03 Python
mysql序号rownum行号实现方式
2022/12/24 MySQL