常见的查找算法以及分块搜索算法的简明教程

news2024/11/20 6:16:55

顺序查找

最基本的查找算法

举例

    // 顺序查找
    public static int searchSequence(int[] arr, int target) {
        int i = 0;
        for (int arr2 : arr) {
            if (arr2 == target) {
                return i;
            }
            i++;
        }
        return -1;
    }

二分查找

[! warning]
值得注意的是这个二分查找算法只对无重复元素的递增或递减的数组有效, 所以我们使用的时候要保证这个数组是有序的, 我们可以利用 Arrays.sort 来对这个数组进行排序,sort 的默认排序是递增排序

最简单的二分查找算法
举例

    // 二分查找,只能对排序算法使用,使用前我们需要先对这个数组进行排序
    public static int searchBinary(int[] arr, int target) {
        Arrays.sort(arr);
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (arr[mid] == target) {
                return mid;
            } else if (target < arr[mid]) {
                right = mid - 1;
            } else if (target > arr[mid]) {
                left = mid + 1;
            }
        }
        return -1;
    }

二分查找的扩展插值查找

二分算法的优化, 通过逼近来实现这个查找
关键代码是
int mid = left + (target - a[left]) / (a[right] - a[left]) * (right - left);
这个与二分搜索算法类似, 本质上就是中值不太一样,

二分查找的扩展斐波那契查找

利用 0.618 的分割比进行查找这个数字
关键代码是
int mid =(int)((right - left) * (1.0 / 1.618) + left) ;

三种二分查找算法的优缺点是什么

二分查找算法

二分搜索算法(Binary Search)是一种在有序数组中查找特定元素的常用算法。它通过将数组不断分割为两半,并比较目标值与中间元素的大小关系来确定目标值所在的区间,从而逐步缩小搜索范围。以下是二分搜索算法的优缺点:
优点:
1. 效率高:二分搜索算法的时间复杂度为 O(log n),其中 n 是数组的长度。由于每次搜索都将搜索范围减半,因此它相对于线性搜索具有更高的效率。
2. 简单:二分搜索算法的实现相对简单,只需递归地分割数组并进行比较即可。
缺点:
1. 仅适用于有序数组:二分搜索算法要求数组是有序的,如果数组未排序,则需要先进行排序操作。
2. 需要额外的空间:二分搜索算法通常需要递归调用,因此可能需要额外的函数调用栈空间。
3. 不适用于插入或删除操作:二分搜索算法用于查找特定元素,但不适用于在数组中插入或删除元素。每次插入或删除操作后,数组可能会被改变,导致结果不准确。

插值搜索算法

插值搜索算法(Interpolation Search)是一种在有序数组中根据目标值的估计位置进行搜索的算法,它不是简单地将数组分割为两半,而是根据目标值与数组中元素的关系来动态计算估计位置。以下是插值搜索算法的优缺点:
优点:
1. 更快的平均搜索时间:插值搜索算法通过根据目标值的估计位置来确定搜索范围,因此平均情况下比二分搜索算法更快。
2. 在数据分布均匀时效果好:当数组中元素分布均匀且接近线性时,插值搜索算法的效果最佳。
缺点:
1. 对数据分布敏感:插值搜索算法对于数据分布不均匀的情况下效果可能很差,甚至可能比二分搜索算法更慢。
2. 可能导致不必要的比较:由于插值搜索算法根据估计位置来确定搜索范围,如果估计位置不准确,可能会导致不必要的比较操作。

斐波那契数列算法

斐波那契查找算法(Fibonacci Search)是一种在有序数组中进行查找的算法,它使用了斐波那契数列来确定搜索范围。与二分搜索和插值搜索相比,斐波那契查找算法有以下优缺点:
优点:
1. 更好的适应性:斐波那契查找算法对于分布不均匀且未知的数据集更具适应性。在某些情况下,它比二分搜索和插值搜索算法更快。
2. 减少比较次数:在某些情况下,斐波那契查找算法的平均比较次数较少,因为它动态调整搜索区间。
缺点:
1. 需要额外的空间:斐波那契查找算法需要预先计算斐波那契数列,这可能需要额外的空间来存储数列。
2. 对于小规模数据不如二分搜索:当数据规模较小时,斐波那契查找算法的性能可能不如简单的二分搜索算法。
3. 不适用于插入和删除操作:与二分搜索和插值搜索一样,斐波那契查找算法也不适用于在数组中执行插入或删除操作。

总结

二分搜索算法在大多数情况下都是一个可靠且高效的选择,特别是对于有序数组的查找操作。插值搜索算法在数据分布均匀的情况下可能会提供更好的性能,但在数据分布不均匀的情况下可能会导致不准确的结果。
斐波那契查找算法在某些情况下可以提供更好的性能,特别是在数据分布不均匀且未知的情况下。然而,它需要更多的空间和计算成本,并且不适用于插入和删除操作

分块查找

分块查找的应用场景

分块查找算法(Block Search)是一种在分块有序表中进行查找的算法。它将数据集划分为若干块(或称为块),每个块内部元素有序,但块与块之间不一定有序。对于一个给定的查找元素,首先确定其所在的块,然后在该块内进行查找。这使得分块查找算法在某些特定的应用场景下具有优势:

  1. 数据集较大且有序:分块查找算法适用于较大的有序数据集。通过将数据划分为块,可以快速缩小查找范围,提高查找效率。
  2. 块内元素相对较少:在每个块内,元素的数量相对较少。这使得块内查找的时间复杂度较低,从而进一步提高了整体查找效率。
  3. 需要频繁的插入和删除操作:分块查找算法相对于二分搜索等其他算法较容易处理插入和删除操作。因为只需要对块内进行相应的插入和删除操作,而不需要改变其他块的顺序。
    分块查找算法常见的应用场景包括:
  • 文件系统:在文件系统中,可以将文件按照某种规则划分为块,利用分块查找算法快速定位所需文件。
  • 图书馆索引:图书馆中的书籍可以按照分类号等信息进行分块,利用分块查找算法进行快速检索。
  • 路由表查找:在网络路由中,可以将路由表按照某种规则划分为块,利用分块查找算法快速查找匹配的路由项。
    需要注意的是,分块查找算法适用于特定场景,对于一般的有序数组查找可能并不是最优选择。因此,在使用分块查找算法时需要根据具体应用场景和问题特点进行合理选择。

分块查找的介绍

就是将数组中的数据划分为几个块, 前一个块的所有数据小于后一个块的所有数据, 我们以每一个块的最大值来进行分割
image.png

image.png

[!example]
下面的这个例子, 其实不太恰当, 只是为了描述这个分块查找的思想, 其实分块查找难点不在于如何查找, 难点在于如何分块, 如何将这个数组划分成满足前一个块的数据小于后一个块的数据. 这才是难点, 我的例子避去了这一点, 只是简单的对这个如何排序做了编辑

package heima_study.day3算法查找排序;

import java.util.Objects;
import java.util.Scanner;

public class 分块查找 {
    public static void main(String[] args) {
        int[] arr = { 16, 5, 9, 12, 21, 18,
                32, 23, 37, 26, 45, 34,
                50, 48, 61, 52, 73, 66 };
        block[] brr = new block[3];
        brr[0]=new block(21, 5, 0, 5);
        brr[1]=new block(45, 23, 6, 11);
        brr[2]=new block(73, 48, 12, 17);
        
        int target;
        Scanner input = new Scanner(System.in);
        target = input.nextInt();
        int i = searchBlock(brr, target);
        if (i != -1) {
            //查找成功
            int result = searchAll(arr, target, brr[i].getStart(), brr[i].getEnd());
            System.out.println(result);
        } else {
            System.out.println(-1);
        }
        input.close();
        
    }

    public static int searchAll(int[] arr, int target, int start, int end) {
        for (int i = start; i <= end; i++) {
            if (arr[i] == target) {
                return i;
            }
        }
        return -1;
    }
    public static int searchBlock(block[] brr,int target){
        for (int i = 0; i < brr.length; i++) {
            if (target < brr[i].getMax() && target > brr[i].getMin()) {
                //说明是在这个块里面
                return i;
            }
        }
        return -1;
    }
    
}

class block {
    private int max;
    private int min;
    private int start;
    private int end;

    public block() {
    }

    public block(int max, int min, int start, int end) {
        this.max = max;
        this.min = min;
        this.start = start;
        this.end = end;
    }

    public int getMax() {
        return this.max;
    }

    public void setMax(int max) {
        this.max = max;
    }

    public int getMin() {
        return this.min;
    }

    public void setMin(int min) {
        this.min = min;
    }

    public int getStart() {
        return this.start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getEnd() {
        return this.end;
    }

    public void setEnd(int end) {
        this.end = end;
    }


    @Override
    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof block)) {
            return false;
        }
        block block = (block) o;
        return max == block.max && min == block.min && start == block.start && end == block.end;
    }

    @Override
    public int hashCode() {
        return Objects.hash(max, min, start, end);
    }

    @Override
    public String toString() {
        return "{" +
            " max='" + getMax() + "'" +
            ", min='" + getMin() + "'" +
            ", start='" + getStart() + "'" +
            ", end='" + getEnd() + "'" +
            "}";
    }   

}

分块查找的补充

在学习这个分块查找的时候, 我对于这个分块查找的原理还不是特别的清楚, 于是我就去网上查找资料,
在分块查找这个网页里面看到了一个较好的解释, 并且它提供了一个个人感觉还是不错的划分块的方法
我在这里不对这个页面的内容过多介绍, 感兴趣的可以自己去了解一下, 我主要是对它代码使用的方法进行一个总结
作者使用的类是

public class BlockSearch {
    private int[] index;  //索引表
    private ArrayList[] list; //存放每个块的元素
}

它首先建立了一个索引表

int[] index = { 10, 20, 30 };

这个索引表刚开始看会感觉有点懵, 不知道它是干什么的, 其实这个索引表就是原作者为这个块划分的最大元素, 它自己定义了三个块, 每个块的最大元素由自己决定, 然后不断向里面添加元素

        blockSearch.insert(1);
        blockSearch.insert(12);
        blockSearch.insert(22);
       
        blockSearch.insert(9);
        blockSearch.insert(18);
        blockSearch.insert(23);
        ……………………

添加的元素通过二分搜索法确定这个元素所属的块

    private int binarySearch(int data) {
        int start = 0;
        int end = index.length;
        int mid = -1;
        while (start <= end) {
            mid = (start + end) / 2;
            if (index[mid] > data) {
                end = mid - 1;
            } else {
                // 如果相等,也插入在后面
                start = mid + 1;
            }
        }
        return start;
    }

举个例子:如果大于 10 小于 20 就属于第二个块, 返回 1, 然后向 list[1]里添加元素
通过这样的一个巧妙方法, 就实现了这个分块
不过这种分块方式也有自己的缺点, 就是这个大小你要自己调整, 同时块的数量也要自己去定义.
不过我感觉这个真的是已经很好了. 感觉很适合新手去理解这个分块搜索算法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1017591.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

常用的辅助类(必会)

1.CountDownLatch package com.kuang.add;import java.util.concurrent.CountDownLatch;//计数器 减法 public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {//总数是6&#xff0c;必须要执行任务的时候&#xff0c;再使用…

ARM接口编程—ADC(exynos 4412平台)

ADC简介 ADC ADC(Analog to Digital Converter)即模数转换器&#xff0c;指一个能将模拟信号转化为数字信号的电子元件 ADC主要参数 分辨率 ADC的分辨率一般以输出二进制数的位数来表示&#xff0c;当最大输入电压一定时&#xff0c;位数越高&#xff0c;分辨率越高&#xf…

全国职业技能大赛云计算--高职组赛题卷①(私有云)

全国职业技能大赛云计算--高职组赛题卷①&#xff08;私有云&#xff09; 第一场次题目&#xff1a;OpenStack平台部署与运维任务1 基础运维任务&#xff08;5分&#xff09;任务2 OpenStack搭建任务&#xff08;15分&#xff09;任务3 OpenStack云平台运维&#xff08;15分&am…

LC142. 环形链表 II

题目大意 给你一个链表&#xff0c;要求判断是否有环&#xff0c;若有环&#xff0c;找出环的入口结点。 142. 环形链表 II 判断是否有环 判环比较简单&#xff0c;用一个一次走一个结点的快指针&#xff0c;和一个一次走一个结点的慢指针同时遍历链表&#xff0c;若两指针相…

第一个Three的demo实例

Three的第一个Demo 前言效果图1、导入threejs2、创建场景3、创建相机4、创建渲染器5、创建几何图形6、创建材质7、创建网格8、将网格添加到场景中9、设置相机的位置10、渲染11、整体代码 前言 创建第一个demo实例—旋转的方格 效果图 1、导入threejs import * as THREE from…

漏洞赏金猎人开源工具集合,自动辅助渗透测试工具

漏洞赏金猎人开源工具集合&#xff0c;自动辅助渗透测试工具。 公开收集的一个国外白帽子用的比较多的开源工具列表 这是一款半自动渗透测试的工具&#xff0c;当前版本多用于渗透测试的信息搜集&#xff0c;每周保持更新&#xff0c;最终的目标是类似于linpeas的全自动渗透测…

直接插入排序、希尔排序详解。及性能比较

直接插入排序、希尔排序详解。及性能比较 一、 直接插入排序1.1 插入排序原理1.2 代码实现1.3 直接插入排序特点总结 二、希尔排序 ( 缩小增量排序 )2.1 希尔排序原理2.2 代码实现2.3 希尔排序特点总结 三、直接插入排序和希尔排序性能大比拼 !!!3.1 如何对比性能&#xff1f;准…

4款视频号数据分析平台!

很多人在做视频号的时候就会有创作参考的需求&#xff0c;那么你们知道视频号中有哪些数据平台&#xff1f;今天就和大家来分享一下 接下来就总结一下视频号数据平台有哪些&#xff1f;排名不分前后。 1&#xff1a;视频号助手&#xff08;channels.weixin.qq.com&#xff09…

旋转的正方体-第15届蓝桥杯第一次STEMA测评Scratch真题精选

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第151讲。 第15届蓝桥杯第1次STEMA测评已于2023年8月20日落下帷幕&#xff0c;编程题一共有6题&#xff0c;分别如下&a…

C 风格文件输入/输出---错误处理---(std::clearerr,std::feof,std::ferror,std::perror)

错误处理 清除错误 std::clearerr void clearerr( std::FILE* stream ); 重置给定文件流的错误标志和 EOF 指示器。 参数 stream-要重置错误标志的文件流 返回值 &#xff08;无&#xff09; 调用示例 #include <iostream> #include <cstdio>using names…

微服务保护-降级

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;SpringCloud…

『C语言进阶』指针进阶(二)

&#x1f525;博客主页&#xff1a; 小羊失眠啦 &#x1f516;系列专栏&#xff1a; C语言 &#x1f325;️每日语录&#xff1a;上天是公平的&#xff0c;有付出就有收获 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前言 在上篇指针进阶中&#xff0c;我们对字符指针、指针…

计网 - 图解OSI 七层模型 和 TCP/IP 四层模型

文章目录 OSI 七层模型TCP/IP四层模型图解 OSI图解 TCP/IP小结 OSI 七层模型 OSI&#xff08;开放系统互联模型&#xff0c;Open Systems Interconnection Model&#xff09;是一个用于理解和描述计算机网络体系结构的标准化框架&#xff0c;由国际标准化组织&#xff08;ISO&…

基于Xml方式Bean的配置-beanName个别名配置

SpringBean配置详解 Bean的基础配置 例如前文涉及到的配置文件 <bean id"userService" class"com.example.Service.Impl.UserServiceImpl"/>此时存储到Spring容器&#xff08;singleObjects单例池&#xff09;中的beanName是userService&#xf…

【Java】IDEA 将 Java 项目打包成 Jar 包

在工件中添加 JAR 构建&#xff08;Build&#xff09;工件&#xff0c;JAR 包会生成在 out 目录下

【系统架构】什么是集群?为什么要使用集群架构?

什么是集群&#xff1f;为什么要使用集群架构&#xff1f; 1.什么是集群&#xff1f;2.为什么要使用集群&#xff1f;2.1 高性能2.2 价格有效性2.3 可伸缩性2.4 高可用性2.5 透明性2.6 可管理性2.7 可编程性 3.集群的常见分类3.1 负载均衡集群3.2 高可用性集群3.3 高性能计算集…

Vue2+Vue3

文章目录 Vue快速上手Vue是什么第一个Vue程序插值表达式Vue核心特性&#xff1a;响应式 Vue指令v-htmlv-show 与 v-ifv-else 与 v-else-ifv-onv-bindv-forv-model指令修饰符 计算属性watch侦听器&#xff08;监视器&#xff09;watch——简写watch——完整写法 Vue生命周期 和 …

c语言输出杨辉三角

#include<stdio.h> int main() {int x 0; //表示杨辉三角的的大小int y 1;printf("请输入x的值: ");scanf("%d", &x);for (int i 0; i < x; i) {for (int j 0; j < i; j) {if (j 0 || i 0) {y 1;}else {y y * (i - j 1) / j;}pri…

[mockjs]-mockjs的使用

Mock主要是用于前后端分离时&#xff0c;模拟交互时的返回数据 接下来介绍一下其它几种Mock的方式 json-server 与 express 之前介绍过json-server,可以启动一个express创建的mock的服务&#xff0c;通过接口获取数据&#xff1b;json-server也可以通过命令直接启动一个json…

【深度学习】大模型卷到机器人上了

当一项变革性技术出现后&#xff0c;以此为基础的技术就会像雨后春笋般蔓延。 就像Transformer出现后&#xff0c;以此为基础的大语言模型ChatGPT&#xff0c;视觉基础模型Segment Anything相继横空出世&#xff0c;并展现出强大的涌现能力。生成式AI可谓百花齐鸣&#xff0c;…