查找

news2024/12/25 13:54:08

章节目录:

    • 一、线性查找
      • 1.1 概述
      • 1.2 代码示例
    • 二、二分查找
      • 2.1 概述
      • 2.2 代码示例
    • 三、插值查找
      • 3.1 概述
      • 3.2 代码示例
    • 四、斐波那契查找
      • 4.1 概述
      • 4.2 代码示例
    • 五、结束语

一、线性查找

1.1 概述

  • 线性查找又称顺序查找,是一种最简单的查找方法,它的基本思想是从第一个记录开始,逐个比较记录的关键字,直到和给定的K值相等,则查找成功;若比较结果与文件中n个记录的关键字都不等,则查找失败。
  • 该算法的优点是简单,缺点是效率较低

1.2 代码示例

public class SeqSearch {

    public static void main(String[] args) {
        int[] array = {1, 2, 3, 5, 6, 7};
        int index = seqSearch(array, 2);
        System.out.println("index=" + index);
        // index=1
    }

    public static int seqSearch(int[] array, int val) {
        for (int i = 0; i < array.length; i++) {
            // 找到值则返回索引。
            if (val == array[i]) {
                return i;
            }
        }
        return -1;
    }
}

二、二分查找

2.1 概述

  • 二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列
  • 示意图(与顺序查找的对比):

在这里插入图片描述

2.2 代码示例

public class BinarySearch {

    public static void main(String[] args) {
        int[] array = {1, 8, 10, 89, 1000, 1000, 1234};
        List<Integer> indexs = binarySearch(array, 0, array.length - 1, 1000);
        System.out.println("indexs=" + indexs);
        // indexs=[4, 5]
    }

    /**
     * 二分查找。
     *
     * @param array   数组
     * @param left    左端索引
     * @param right   右端索引
     * @param findVal 查找的值
     * @return {@link List}<{@link Integer}>
     */
    public static List<Integer> binarySearch(int[] array, int left, int right, int findVal) {

        // 整个递归查找阶段结束都没有找到值。
        if (left > right) {
            return Collections.emptyList();
        }

        // 1.找到中间值。
        int midIndex = (left + right) / 2;
        int midVal = array[midIndex];

        // 2.如果查找的值小于中间值则向左递归,否则向右进行递归查找。
        if (findVal < midVal) {
            return binarySearch(array, left, midIndex - 1, findVal);
        } else if (findVal > midVal) {
            return binarySearch(array, midIndex + 1, right, findVal);
        } else {

            // 3.若查找的值等于中间值,再继续看有没有相同值。
            List<Integer> indexs = new ArrayList<>();

            // 继续向左扫描。
            int pointer = midIndex - 1;
            while (pointer > 0 && array[pointer] == findVal) {
                indexs.add(pointer);
                // 左移。
                pointer--;
            }

            // 存入当前中间值。
            indexs.add(midIndex);

            // 继续向右扫描。
            pointer = midIndex + 1;
            while (pointer < (array.length - 1) && array[pointer] == findVal) {
                indexs.add(pointer);
                // 右移。
                pointer++;
            }

            return indexs;
        }
    }
}

三、插值查找

3.1 概述

  • 插值查找,有序表的一种查找方式,插值查找是根据查找关键字与查找表中最大最小记录关键字比较后的查找方法。
  • 插值查找基于二分查找,将查找点的选择改进为自适应选择,提高查找效率。
  • 公式优化
             low+high         1
      mid =  ———————— = low + —(high-low)
                2             2

                  optimize
                      ⇩


              findVal-array[low]
mid = low + —————————————————————— (high-low)
            array[high]-array[low]

  • 注意事项:对于数据量较大关键字分布比较均匀的查找表来说,采用插值查找, 速度较快。而关键字分布不均匀的情况下,该方法不一定比折半查找要好。

3.2 代码示例

public class InsertValueSearch {

    private static int counter = 0;

    public static void main(String[] args) {
        int[] array = {1, 8, 10, 89, 1000, 1000, 1234};
        int index = insertValueSearch(array, 0, array.length - 1, 1234);
        System.out.println("search count=" + counter + ",index=" + index);
        // search count=1,index=6
    }

    public static int insertValueSearch(int[] array, int left, int right, int findVal) {

        counter++;

        // < array[0] || > array[array.length - 1] 是为了防止中间索引越界。
        if (left > right || findVal < array[0] || findVal > array[array.length - 1]) {
            return -1;
        }

        // 1.与二分查找不同,这里通过公式自适应计算出中间值。
        int midIndex = left + (right - left) * (findVal - array[left]) / (array[right] - array[left]);
        int midVal = array[midIndex];

        // 2.向左向右递归查找。
        if (findVal < midVal) {
            return insertValueSearch(array, left, midIndex - 1, findVal);
        } else if (findVal > midVal) {
            return insertValueSearch(array, midIndex + 1, right, findVal);
        } else {
            return midIndex;
        }
    }
}

四、斐波那契查找

4.1 概述

黄金分割点是指把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是 0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割,也称为中外比。这是一个神奇的数字,会带来意向不大的效果。

  • 斐波那契搜索(Fibonacci search) ,又称斐波那契查找,是区间中单峰函数的搜索技术。
  • 斐波那契查找原理与前两种相似,仅仅改变了中间结点(mid)的位置,mid 不再是中间或插值得到,而是位于黄金分割点附近,即 mid=low+F(k-1)-1(F 代表斐波那契数列)。
  • 斐波那契搜索就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数 F[n],将原查找表扩展为长度为 F[n] (如果要补充元素,则补充重复最后一个元素,直到满足F[n]个元素),完成后进行斐波那契分割,即 F[n] 个元素分割为前半部分 F[n-1] 个元素,后半部分 F[n-2] 个元素,找出要查找的元素在那一部分并递归,直到找到。
  • 斐波那契数列指的是这样一个数列:1,1,2,3,5,8,13,21,34,55,89… (这个数列从第3项开始每一项都等于前两项之和。)
  • 示意图

在这里插入图片描述

  • 由斐波那契数列 F[k]=F[k-1]+F[k-2] 的性质,可以得到 (F[k]-1) = (F[k-1]-1) + (F[k-2]-1) +1 。该式说明:只要顺序表的长度为 F[k]-1,则可以将该表分成长度为 F[k-1]-1F[k-2]-1两段,即如上图所示。从而中间位置为 mid=low+F(k-1)-1
  • 类似的,每一子段也可以用相同的方式分割;
  • 但顺序表长度 n 不一定刚好等于 F[k]-1,所以需要将原来的顺序表长度 n 增加至 F[k]-1。这里的 k 值只要能使得 F[k]-1 恰好大于或等于 n 即可,顺序表长度增加后,新增的位置(从 n+1F[k]-1 位置),都赋为 n 位置的值即可。

4.2 代码示例

public class FibonacciSearch {

    public static void main(String[] args) {
        int[] arr = {1, 8, 10, 89, 1000, 1234};
        System.out.println("index=" + fibSearch(arr, 1));
        // index=0
    }

    private static int[] getFib(int size) {
        if (3 > size) {
            throw new IllegalArgumentException("size it has to be greater than or equal to 3.");
        }
        int[] fib = new int[size];
        // 前两个数固定为1。
        fib[0] = 1;
        fib[1] = 1;
        // 从第三个数开始赋值。
        for (int i = 2; i < fib.length; i++) {
            // 当前值等于前两个数的和。
            fib[i] = fib[i - 1] + fib[i - 2];
        }
        return fib;
    }

    public static int fibSearch(int[] array, int findVal) {
        int low = 0;
        int high = array.length - 1;
        int[] fib = getFib(20);
        // 记录斐波那契分隔数值的下标。
        int k = 0;
        // 用于记录中间索引。
        int midIndex = 0;

        // 1.找到斐波那契数值的下标。
        while (high > fib[k] - 1) {
            k++;
        }

        // 2.拷贝完整长度的数组,当值的数量不够长度时默认填充为0进行占位。
        int[] temp = Arrays.copyOf(array, fib[k]);

        // 3.填充temp数组中为0数值。
        // 假设当前temp={1,8,10,89,1000,1234, 0,0}  => 填充后得到:{1,8,10,89,1000,1234, 1234,1234}
        for (int i = high + 1; i < temp.length; i++) {
            temp[i] = array[high];
        }

        // 4.开始查找。
        while (low <= high) {
            midIndex = low + fib[k - 1] - 1;
            // 左移。
            if (findVal < temp[midIndex]) {
                high = midIndex - 1;
                k--;
                // 右移。
            } else if (findVal > temp[midIndex]) {
                low = midIndex + 1;
                k -= 2;
            } else {
                // 返回下标。
                return (midIndex <= high) ? midIndex : high;
            }
        }
        return -1;
    }
}

五、结束语


“-------怕什么真理无穷,进一寸有一寸的欢喜。”

微信公众号搜索:饺子泡牛奶

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

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

相关文章

若依框架:前端登录组件与图像验证码|用户登录逻辑

在上一篇《若依框架&#xff1a;前端项目结构与初始页面渲染流程》中&#xff0c;我们探讨了与“vue.config.js文件配置、.env模式和环境变量配置、vue-router全局导航守卫配置、vue-router路由配置简介”相关的内容&#xff0c;书接上回&#xff0c;我们继续探讨若依前端项目的…

【C语言进阶】字符函数与字符串函数

目录 1、函数介绍 1.1 strlen 1.2 strcpy 1.3 strcat 1.4 strcmp 1.5 strncpy 1.6 strncat 1.7 strncmp 1.8 strstr 1.9 strtok 1.10 strerror 【补】字符分类函数&#xff1a; 1.11 memcpy 1.12 memmove 1.13 memcmp 1.14 memset 1、函数介绍 1.1 strlen siz…

基于卷积神经网络的高光谱分类(1D、2D、3D-CNN)

算法原理 卷积神经网络&#xff08;Convolutional Neural Networks&#xff0c;CNN&#xff09;是深度学习中最常见的一种 算法&#xff0c;它具有强大的特征学习能力。CNN 通过结合局部感知区域、共享权重、空间或者 时间上的降采样来充分利用数据本身包含的局部性等特征&…

绘图仪 与 示波器 Plotter Oscilloscope

【后台管理&#xff0c;这哪里是广告了&#xff1f;图都是百度搜的&#xff0c;又没有销售信息&#xff0c;就事论事而已&#xff01;】 Plotter &#xff1a; 对低频信号持续测量并绘制到一张很长的纸上&#xff0c;通常是卷纸。 常见的比如传统心电图机&#xff08;图左&am…

『分分钟玩转VueRouter●下』我对VueRouter在项目中如何使用的理解

路由的设置会根据系统中用户角色的数量而有所不同&#xff0c;大致分为三种单角色同权限、单角色不同权限、多角色。这里的角色均是只一种身份&#xff0c;而不是用户量。接下来的讲解纯属个人见解&#xff0c;大型项目会将不同权限的用户直接分开开发不同的系统。如果是小型多…

c++基础——for循环

for循环是循环的一种 以下是 for 循环的结构&#xff1a; for (初始化; 判断条件; 更新) {循环体; } 执行顺序&#xff1a; for 语句的三个部分中&#xff0c;任何一个部分都可以省略。其中&#xff0c;若省略了判断条件&#xff0c;相当于判断条件永远为真。 for (int i …

fpga实操训练(从模块到系统开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们学习了fpga的一些基本操作&#xff0c;熟悉了这些操作&#xff0c;基本上说fpga已经入门了。但是距离我们用fpga开发产品&#xff0c;这中…

Faster RCNN网络源码解读(Ⅷ) --- RPN网络代码解析(下)RegionProposalNetwork类解析

目录 一、代码作用&#xff08;rpn_function.py&#xff09; 二、代码解析 2.1 RegionProposalNetwork类 2.1.1 正向传播过程forward 接着上篇博客的2.1.2节 2.1.2 assign_targets_to_anchors 2.1.3 det_utils.Matcher传入参数 2.1.4 compute_loss 2.1.5 smooth_l1_lo…

你真的会正确使用wait和notify么?

目录 wait和notify原理 API wait 与 sleep的区别 wait 和 notify的正确使用 step1 step2 step3 step4 step5 总结waitnotify wait和notify原理 当我们线程获取某个对象的monitor锁的时候就会成为owner线程,当owner线程条件不满足的时候,就会调用wait方法,该线程就会进…

惠州市政企信息化(互联网)市场调研报告

1.引言 1.1.编写目的 据广东省惠州市惠东县的政企信息化市场调研的客观性数据&#xff0c;分析相关数据&#xff0c;确定市场规模、市场潜力、市场需求&#xff0c;以及需求价值&#xff0c;为后续的市场决策、服务组合决策提供依据&#xff0c;也作为未来根据市场变化而调整…

Nacos 注册中心

Nacos 注册中心 目录概述需求&#xff1a;设计思路实现思路分析1.增加 Maven 依赖2.Client端配置注册中心3.Server端配置注册中心4.Nacos 注册中心参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c…

Java--Map接口详解

目录 Map接口的特点 代码实现 代码实现 Map的常用方法 代码实现 Map接口的4种遍历方法 代码实现 第一种方式 第二种方式 第三种方式 第四种方式 Map接口的特点 1)Map与Collection并列存在。用于保存具有映射关系的数据&#xff1a;Key-Value 2)Map中的key和value可以…

如何在星巴克连接家中Windows台式机?(安卓,iOS, Windows, macOS配合frp穿透公网IP实现)

zhaoolee 最近热衷于和海外热心老哥们交换硬盘中的单机游戏资源&#xff08;BT下载&#xff09;&#xff0c;家中有Windows台式机&#xff0c; 适合长时间挂机下载BT资源&#xff0c;zhaoolee希望能随时连接到Windows台式机新增下载任务&#xff0c;安装体积超大的主机游戏。 …

End-to-End Object Detection with Transformers论文阅读笔记

End-to-End Object Detection with Transformers 端到端&#xff0c;不需要NMS后处理了&#xff0c;直接出结果。 1、Abstract 将目标检测作为一个集合预测问题来解决。简化了检测的整体流程&#xff0c;有效的消除了许多人工设计的部分&#xff0c;比如NMS&#xff0c;anch…

数据库连接池(C++11实现)

目的&#xff1a; 因为对数据库的操作实质上是对磁盘的IO操作&#xff0c;所以如果对数据库访问次数过多&#xff0c;就会到导致大量的磁盘IO&#xff0c;为了提高MySQL数据库&#xff08;基于C/S设计&#xff09;的访问瓶颈&#xff0c;除了在服务器端增加缓存服务器缓存常用的…

还在用BERT做文本分类?分享一套基于预训练模型ERNIR3.0的文本多分类全流程实例【文本分类】

目录&#x1f340;一、前言&#x1f331;二、多分类场景简介&#x1f343;三、前期准备阶段&#x1f7e5;3.1 运行环境准备&#x1f7e7;3.2 文心ERNIE系列模型介绍&#x1f7e8;3.3 预训练模型加载⬜3.4 加载项目代码&#x1f490;四、数据准备阶段&#x1f7e9;4.1 数据处理流…

变不可能为可能——记房产推销员佟鑫海

有勤奋&#xff0c;就会有所收获。傲人的成绩和背后的努力密切相关。俗话说得好&#xff0c;没卖不掉的房子&#xff0c;仅有卖不掉房子的艺人经纪人。关键是你是否有恒心。 在明升&#xff0c;总会有这样一群影子&#xff0c;他们每天精力旺盛&#xff0c;衣着光鲜&#xff0…

【C/C++ SOCKET编程】基于TCP协议实现服务器客户端的简单通信

什么是SOCKET Socket又称"套接字"&#xff0c;应用程序通常通过"套接字"向网络发出请求或者应答网络请求&#xff0c;使主机间或者一台计算机上的进程间可以通讯。 TCP/IP协议 从字面意义上讲&#xff0c;有人可能会认为 TCP/IP 是指 TCP 和 IP 两种协议…

unsafe.Pointer和uintptr的区别

unsafe 包 func Alignof(x ArbitraryType) uintptr func Offsetof(x ArbitraryType) uintptr func Sizeof(x ArbitraryType) uintptr type ArbitraryType int type Pointer *ArbitraryType在unsafe包中&#xff0c;只提供了3个函数&#xff0c;两个类型。就这么少的量&#xf…

【数据结构进阶】布隆(Bloom Filter)过滤器【哈希+位图的整合】

布隆(Bloom Filter)过滤器【哈希位图的整合】 1、什么是布隆过滤器&#xff1f; 布隆过滤器&#xff08;Bloom Filter&#xff09;是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空…