查找算法 - 总纲

本文介绍了二分查找、插值查找和斐波那契查找在有序数据中的高效应用,以及索引(稠密、分块和倒排)在海量数据检索中的角色。同时,探讨了二叉排序树、B树和B+树在不同场景下的优势,以及散列表的优缺点。最后,总结了各种技术在性能上的比较和常见使用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.0、二分查找算法:
前提:是“有序”的元素列表
原理:每次都与“中间的数”比较看是大了还是小了,下一次的猜测直接排除一半的可能,从另外一半继续查找,重复这个过程,直到查找成功或者查找集为空
适用场景:本身就是有序的存储,或者维持有序的代价不高,就可以用这个,很快(太简单的直接顺序查找即可)
时间复杂度:logN

1.1、插值查找算法 -》 二分查找算法的特制版,但是除了二分查找算法的限制外,还需要分布均匀:
前提:是“有序”的“知道界限”的元素列表,元素大小分布需要比较均匀
原理:和二分查找原理差不多,只是分割点的选择不同(不再是中间,而是根据公式选择一个位置,会找到更靠近查找值的位置,所以前提是分布均匀),中间分割点是根据一个公式计算得出,公式可以去看"大话数据结构",
适用场景:本身就是有序的存储,或者维持有序的代价不高,元素大小分布均匀,就可以用这个代替二分查找算法
时间复杂度:logN , 虽然时间复杂度和二分查找算法差不多,但在元素比较多且分布比较均匀的时候,实际效率比二分查找好很多

1.2、斐波那契查找算法 -》:二分查找算法的特制,需要是斐波那契数列
前提:元素的排列是斐波那契数列,斐波那契数列指的是这样一个数列 - 从第3项开始,每一项都等于前两项之和。
原理:和二分查找原理类似,只是分割点的选择不同,详细的可以去看"大话数据结构"
适用场景:斐波那契数列
时间复杂度:logN , 虽然时间复杂度和二分查找算法差不多,但因为计算公式比二分查找、插值查找简单,海量数据下效率更高

2、对于海量数据,上面的算法查找还需要几次比较,维持有序的代价也比较高,用索引可以更快(需要查询事前维持)
稠密索引:索引项与数据集的记录个数相同,一一对应,普通的索引方式;可以通过二分查找、插值查找
分块索引:块间有序,块内无序(块内也可以有序,但那样代价高昂);减少了索引个数;索引结构有- 块内最大值、块内元素个数、块首数据元素的指针;可以通过二分查找、插值查找先找到块,再通过顺序查找找到记录
倒排索引:单词表 - 存储具有相同关键字的对应的所有记录号,根据属性值找到所有记录。

3、二叉排序树 - 上面算法只是应对查找用的,而二叉排序树增删查都很有效率;特别是平衡二叉树,高度更低,查找效率更高;但维持绝对的平衡代价太高,一般相对平衡即可(红黑树):
二叉排序树:左子树为空或者所有左节点值小于根节点的值,右子树为空或者所有右节点值大于根节点的值,其左右子树也是二叉树
高度平衡二叉树:每一个节点的左子树和右子树的高度差最多==1;每个节点的左子树和右子树也都是高度平衡二叉树
红黑树:一种含有红黑结点并能自平衡的二叉排序树(黑色完美平衡),这个用得多
说起红黑树,不得不说redis的跳表(红黑树的替代品,但实现更加简单,范围查询方便;原理就是多级的链表  https://www.cnblogs.com/cxy2020/p/13799047.html

4.0、B树 -》 平衡多叉树,二叉排序树是内存中用的,如果是海量数据,就要考虑到磁盘交互问题,这是重点,一次读取多个会比较好(每次硬盘读取的都是一个或多个页面,每个页的长度是211到214的字节)
但是B树不适合遍历、范围查找,B+树出现了

4.1、B+树 -》 B+树是B树的一个升级版,B+树更充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找。
规则:
1)B+ 树非叶子节点上是不存储关键字的,仅存储分块的最大键值以及指针,而 B 树节点中不仅存储分块的指针,也会存储关键字
2)B+ 树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的
一般根节点都是常驻内存的,开始不需要到磁盘中读取数据,直接从内存中读取即可。

5、散列hash表 -》 存储位置与关键字之间建立一个关系,使关键字对应到相应的存储位置上
地址冲突了,一般采用链地址法(有最佳的查找性能)
重要因素:
1)散列函数是否均匀
2)装填因子要小,大于0.75需要扩容
大多数的时候散列表查找性能最佳,但是不适合的场景是"关键字重复度高"、“范围查找”,它只适合一对一查找

 

按照性能来看,散列hash最好(直接寻址),索引查找,磁盘交互用B+树 / 内存增删查用红黑树,有序序列的查找用二分/插值/斐波那契,实在不行直接顺序查找;一般都是组合使用(比如kafka根据offset找数据就是通过有序offset+segment+二分查找+分块索引+二分查找+稠密索引+顺序查找

 

二分查找的代码实现:

    private static int binarySearch(int[] arr, int key) {
        int low = 0;
        int high = arr.length - 1;

        while (low <= high) {
            int mid = (low + high) / 2;

            if (arr[mid] == key) {
                return mid;
            } else if (arr[mid] > key) {
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }

        // 查找失败,返回 -1
        return -1;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值