【PHP数据结构】线性查找与二分查找

欢迎来到查找的世界,在学习完各类数据结构以后,总算走到了这一步,不知道你们有什么感想呢?反正我是边学边忘,如今让我去说说图的那几个算法仍是在蒙圈的状态中。不过学习嘛,就是一步一步的来,暂时搞不懂的东西其实也是能够放一放的。打破砂锅和坚持不懈固然是好的品德,但有些东西可能真的是须要时间去消化的,甚至多是须要真实的项目经历才能完全搞明白。在咱们编程行业来讲就是典型的这种实践的学习形式效果会更好,不少人在上大学的时候对于数据结构以及其它专业课都是以死记硬背为主,包括上了多少年班的同窗可能都没有在业务代码中真正的使用过什么算法,因此理解它们确实是很是困难的。这时,咱们能够暂时休息一下,转换一下思路,学习最主要的就是预习和复习,在此次学习完以后,未来再进行屡次的复习,研究各类不一样的资料,早晚有一天你们都能搞明白的。php

今天的内容其实就很是简单了,能够说是除了线性表以外最简单的内容。咱们只研究两个很是初级的查找,那就是顺序查找和折半查找。相信很多同窗可能早就会了,通常培训机构讲数据结构和算法时,查找必讲二分,排序必讲冒泡,更不用说正规大学对口专业出身的同窗了。固然,这两个也是很是简单的,无论你有没有基础,我们一块儿来看看吧。git

无论你是什么算法题,仍是在实际的业务开发中,查找都是很是重要的,甚至可能比排序还要重要。想一想你成天面向数据库编程是在干吗?不就是 CRUD 嘛,其中大部的业务还都是以搜索查找居多,咱们在优化数据库时,也主要是优化各类查询语句。固然,要说到数据库的查找那就过高深了,之后咱们学习 MySQL 相关的知识时再详细讲解,特别是索引中的 B+ 树,就是数据结构和算法的核心思想的体现。好吧,不吹牛了,也不敢在这里多说了,由于本身也没研究透呢。github

线性查找(顺序查找)

顾名思义,不论是叫线性仍是叫顺序,很明显,就是一条数据一条数据的对比下去就好啦。面试

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) 的排序算法,这样整体的时间复杂度就还能保持在对数级别了。总之,先掌握好这些简单的内容,千万别在面试的时候连这一关都过不了哦!

测试代码:

https://github.com/zhangyue0503/Data-structure-and-algorithm/blob/master/6.查找/source/6.1线性查找与二分查找.php