查找算法——java

news2024/9/22 13:45:23

 顺序查找(顺序表查找) 

顺序查找也称为线形查找,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结    点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。

顺序查找适合于存储结构为顺序存储或链接存储的线性表。

    private static int sequenceSearch(int[] nums, int target) {
        for(int index=0;index<nums.length;index++){
            if (nums[index]==target) return index;
        }
        return -1;
    }

时间复杂度为O(n)

折半查找(有序查找)

折半查找(Binary Search)技术,又称为二分查找。它的前提是线性表中的记录必须是关键码有序(通常从小到大有序) ,线性表必须采用顺序存储。折半查找的基本思想是:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。不断重复上述过程,直到查找成功,或所有查找区域无记录,查找失败为止。 

非递归算法:

    private static int binarySearch1(int[] sortnums, int target) {
        int left=0;
        int right=sortnums.length-1;
        while(left<=right){
            int mid =(left+right)/2;
            if (target==sortnums[mid]) return mid;
            if(target < sortnums[mid]) right=mid-1;
            if (target > sortnums[mid]) left=mid+1;
        }
        return -1;
    }

递归算法:

    private static int binarySearch2(int[] sortnums, int target,int left,int right) {
        if (left <= right){
            int mid=(left+right)/2;
            if(target==sortnums[mid]) return mid;
            if(target<sortnums[mid])  return binarySearch2(sortnums,target,left,mid+1);
            if (target>sortnums[mid]) return binarySearch2(sortnums,target,mid+1,right);
        }
        return -1;
    }

时间复杂度为O(logn)

插值查找(有序查找)

插值查找是根据要查找的关键字key与查找表中最大最小记录的关键字比较后的 查找方法,其核心就在于插值的计算公式mid=low+\frac{target-num[left]]}{nums[right]-nums[left]]}(right-left)

简而言之,基于二分查找算法,将查找点的选择改进为自适应选择。

非递归方法:

    private static int insertSearch1(int[] sortnums, int target) {
        int left=0;
        int right=sortnums.length-1;
        while(left<=right){
            int mid =left+((target-sortnums[left])/(sortnums[right]-sortnums[left]))*(right-left);
            if (target==sortnums[mid]) return mid;
            if(target < sortnums[mid]) right=mid-1;
            if (target > sortnums[mid]) left=mid+1;
        }
        return -1;
    }

递归算法:

    private static int insertSearch2(int[] sortnums, int target, int left, int right) {
        if (left <= right){
            int mid=left+((target-sortnums[left])/(sortnums[right]-sortnums[left]))*(right-left);
            if(target==sortnums[mid]) return mid;
            if(target<sortnums[mid])  return binarySearch2(sortnums,target,left,mid+1);
            if (target>sortnums[mid]) return binarySearch2(sortnums,target,mid+1,right);
        }
        return -1;
    }

查找成功或者失败的时间复杂度均为O(log2 (log2 n))

斐波那契查找(有序)

与二分法、插值排序方法类似,只是关于mid的确定与斐波那契数列有关。

在斐波那契数列中的元素满足这样的关系:F[k]=F[k-1]+F[k-2],此处将这个数组稍微改一下,改成:(F[k]-1)=(F[k-1]-1)+(F[k-2]-1)+1

开始表中记录的个数为某个斐波那契数小1,及len=Fib(k)-1.

斐波那契数列中的数值都是固定的,但要查找的数组的长度不固定,此时需要的是创建新数组,使新数组的长度是斐波那契数列中的值,并且是比原数组长度略大的值,多出来的元素用原数组最高位元素补充

 斐波那契查找算法
1 ) 当 key=nums[mid] 时,查找就成功。
2 ) 当 key<nums[mid]时,新范围是第low个到第mid-1个,此时范围个数为f[k-1]-1个;
3 ) 当 key>nums[mid]时,新范围是第mid+1个到第high个,此时范围个数为f[k-2]-1个。

private static int fibonacciSearch(int[] nums, int target) {
        int len=nums.length;
        //构建特殊的Fibonacci数组,
        ArrayList<Integer> fibo = new ArrayList<Integer>();
        fibo.add(1);
        fibo.add(1);
        int k=2;
        while (true){
            int num=fibo.get(k-1)+fibo.get(k-2);
            fibo.add(num);
            if (fibo.get(k)-1>len) break;
            k++;
        }
        //斐波那契数列的最符合略大于原数组的Fibonacci数f(k)
        int[]temp = Arrays.copyOf(nums,fibo.get(k));
        for (int i=len+1;i<fibo.get(k);i++){
            temp[i]=nums[len-1];
        }
        int start=0;
        int end=len-1;
        while (start<=end){
            int mid=start+fibo.get(k-1)-1;
            if (target==nums[mid]) return mid;
            if (target>nums[mid]) {
                start=mid+1;
                k--;
            }
            if  (target<nums[mid]){
                end=mid-1;
                k-=2;
            }
        }
        return -1;
    }

二叉排序树查询

二叉排序树的性质:

  • 若左子树不空,则左子树上所有结点的键值均小于或等于它的根结点的键值。
  • 若右子树不空,则右子树上所有结点的键值均大于或等于它的根结点的键值。
  • 左、右子树也分别为二叉排序树。

二叉排序树的创建:

    private static void CreateShu(){
        int[] array = {35,76,6,22,16,49,49,98,46,9,40};
        BinaryTree root = new BinaryTree(array[0]);
        for(int i = 1; i < array.length; i++){
            createBST(root, array[i]);
        }
    }

    public static void createBST(BinaryTree root, int element){
        BinaryTree newNode = new BinaryTree(element);
        if(element > root.value){
            if(root.right == null)
                root.right = newNode;
            else
                createBST(root.right, element);
        }else if(element < root.value){
            if(root.left == null)
                root.left = newNode;
            else
                createBST(root.left, element);
        }else{
            System.out.println("该节点" + element + "已存在");
            return;
        }
    }

二叉排序树的查找:

基本思想:

与节点进行比较,等于节点的值则查找成功

大于节点的值则遍历查找节点的左孩子

小于节点的值则遍历查找节点的右孩子

public static void searchBST(BinaryTree root, int target, BinaryTree p){
        if(root == null){
            System.out.println("查找"+target+"失败");
        }else if(root.value == target){
            System.out.println("查找"+target+"成功");
        }else if(root.value >= target){
            searchBST(root.left, target, root);
        }else{ 
            searchBST(root.right, target, root);
        }
    }

分块查找 

分块查找的基本思想:将查找表分为若干子块。块内的元素可以无序,但块之间是有序的,即第一个块中的最大关键字小于第二个块中的所有记录的关键字,第二个块中的最大关键字小于第三个块中的所有记录的关键字,以此类推。再建立一个索引表,索引表中的每个元素含有各块的最大关键字和各块中的第一个元素的地址,索引表按关键字有序排列。

以查找36为例

1.在索引表中依次遍历找到第一个大于它的值,即40

2.移动到40指向的数组区间的第一个元素,即数组下标9

3.从数组下标9开始遍历,40→36 找到36

哈希表查找

哈希表则通过计算一个以记录的关键词为自变量的函数(哈希函数H(x))来得到该机里的存储地址,所以在哈希表中进行查找操作时,需要同一哈希函数计算得到待查记录的存储地址,然后到相应的存储单元去获得有关信息在判定查找是否成功。

通过哈希函数H(key)和处理冲突的方法,将一组关键字映射,形成哈希散列

对于某个哈希函数H和两个关键字K_{1}K_{2},如果K_{1}\neq K_{2},而H(K_{1})=H(K_{2}),则称为冲突。具有相同的哈希函数值的关键字对该哈希函数成为同义词。 

哈希函数的构造 

  • 常见的哈希函数构造方法

        直接定址法、数字分析法、平方取中法、折叠法、随机数法、除留余数法

  • 处理冲突的方法

        (1)开放定址法       

线性探测法可能使第i个哈希地址的同义词存入第i+1个哈希地址,这样本应存入第i+1个哈希地址的元素变成第i+2个哈希地址元素的同义词。

        (2)链地址法:查找表的每一个记录中增加一个链域,链域中存放下一个具有相同哈希函数值的记录的存储地址(对于发生冲突时的查找和插入操作就跟线性表一样)。

        (3)再哈希法:RHi均是不同的哈希函数,即在同一词发生地址冲突时计算另一个哈希函数地址,直到冲突不再发生。

哈希函数的装填因子:α标志着哈希表的装满程度,α越小,发生冲突的可能性越小。

\alpha =表中装入的记录数  / 哈希表的长度

算法思想:key-value存储思想,key存值,value存索引

private static int hashSearch(int[] nums, int target) {
        HashMap<Integer,Integer> hashNums = new HashMap<Integer,Integer>();
        for (int i=0; i<nums.length; i++){
            hashNums.put(nums[i],i);
        }
        if (hashNums.get(target) !=null) return hashNums.get(target);
        return -1;
    }

哈希表的构造方法:

1、直接定址法
  哈希地址:f(key) = a*key+b (a、b为常数)。
2、数字分析法
  假设关键字是R进制数(如十进制)。并且哈希表中可能出现的关键字都是事先知道的,则可选取关键字的若干数位组成哈希地址。选取的原则是使得到的哈希地址尽量避免冲突,即所选数位上的数字尽可能是随机的。
3、平方取中法
  取key平方后的中间几位为哈希地址。通常在选定哈希函数时不一定能知道关键字的全部情况,仅取其中的几位为地址不一定合适。而一个数平方后的中间几位数和数的每一位都相关, 由此得到的哈希地址随机性更大。如key是1234,那么它的平方就是1522756,再抽取中间的3位就是227作为 f(key) 。
4、折叠法
  折叠法是将 key 从左到右分割成位数相等的几个部分(最后一部分位数不够可以短些),然后将这几部分叠加求和,并按哈希表的表长,取后几位作为 f(key) 。
比如key是9876543210,哈希表的表长为3位,我们将 key 分为4组,987 | 654 | 321 | 0 ,然后将它们叠加求和 987+654+321+0=1962,再取后3位即得到哈希位置是:962 。
5、除留余数法
  取关键字被某个不大于哈希表表长 m 的数 p 除后所得的余数为哈希地址。即 f(key) = key % p (p ≤ m)。这种方法是最常用的哈希函数构造方法。

6、随机数法
  哈希地址:random(key) ,这里random是随机函数,当 key 的长度不等时,采用这种方法比较合适。

查找总结:

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

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

相关文章

web服务器nginx下载及在win11的安装

一.背景 还是为了公司安排的师带徒任务。 操作系统版本&#xff1a;win11 家庭版 mginx版本&#xff1a;1.24.0 二.nginx版本选择与下载 我之前也写过下载nginx下载_ngnix stable 下载-CSDN博客 不想看寻找过程的&#xff0c;直接点这里去下载https://nginx.org/download…

抖音视频评论抓取软件|视频批量下载

抖音视频评论采集软件是一款基于C#开发的高效、便捷的工具&#xff0c;旨在为用户提供全面的数据采集和分析服务。该软件不仅支持通过关键词进行搜索抓取&#xff0c;还能够通过分享链接进行单个视频的抓取和下载&#xff0c;让用户轻松获取抖音视频评论数据。 &#x1f50d; …

记录西门子:SCL博图

算术表达式: 关系表达式&#xff1a; 逻辑表达式&#xff1a; 赋值运算

云时代【6】—— 镜像 与 容器

云时代【6】—— 镜像 与 容器 四、Docker&#xff08;三&#xff09;镜像 与 容器1. 镜像&#xff08;1&#xff09;定义&#xff08;2&#xff09;相关指令&#xff08;3&#xff09;实战演习镜像容器基本操作离线迁移镜像镜像的压缩与共享 2. 容器&#xff08;1&#xff09;…

MSCKF3讲:后端理论推导(上)

MSCKF3讲&#xff1a;后端理论推导&#xff08;上&#xff09; 文章目录 MSCKF3讲&#xff1a;后端理论推导&#xff08;上&#xff09;1 MSCKF中的状态变量① IMU状态:② cam0状态&#xff1a;③ IMU和cam0间状态关系 2 微分方程递推&#xff08;数值解&#xff09;3 IMU状态预…

洛谷C++简单题小练习day22—小鱼记忆小程序!一题五解,高效学习

day22--小鱼记忆--2.26 习题概述 题目描述 小鱼最近被要求参加一个数字游戏&#xff0c;要求它把看到的一串数字 ai​&#xff08;长度不一定&#xff0c;以 0 结束&#xff09;&#xff0c;记住了然后反着念出来&#xff08;表示结束的数字 0 就不要念出来了&#xff09;。…

【高级数据结构】Trie树

原理 介绍 高效地存储和查询字符串的数据结构。所以其重点在于&#xff1a;存储、查询两个操作。 存储操作 示例和图片来自&#xff1a;https://blog.csdn.net/qq_42024195/article/details/88364485 假设有这么几个字符串&#xff1a;b&#xff0c;abc&#xff0c;abd&…

数字中国:构建智慧社会的未来蓝图

一、引言 随着信息技术的迅猛发展&#xff0c;数字中国已经成为推动社会进步、提升国家竞争力的重要引擎。数字中国不仅代表着信息技术的广泛应用&#xff0c;更代表着一种全新的社会形态和发展模式。在这个背景下&#xff0c;AI与大数据技术的融合与应用成为数字中国建设的核…

操作系统原理与实验——实验三优先级进程调度

实验指南 运行环境&#xff1a; Dev c 算法思想&#xff1a; 本实验是模拟进程调度中的优先级算法&#xff0c;在先来先服务算法的基础上&#xff0c;只需对就绪队列到达时间进行一次排序。第一个到达的进程首先进入CPU&#xff0c;将其从就绪队列中出队后。若此后队首的进程的…

PCIe(四)—— 物理层

在看完事务层和数据链路层之后,我们来继续我们的协议栈之旅吧!这一篇中,我们会来看看PCIe物理层(Physical Layer)是如何工作的,从而帮助我们更加深入的了解PCIe的数据传输。 1. 物理层(Physical Layer) 当数据链路层将上层数据封装好后,就会将其交给物理层进行传输。…

探讨苹果 Vision Pro 的 AI 数字人形象问题

Personas 的设计模糊性&#xff1a; 部分人认为这种模糊设计可能是出于安全考虑&#x1f6e1;️。安全角度&#xff1a;Personas 代表着你的 AI 数字形象&#xff0c;在创建时&#xff0c;它相当于你的 AVP&#xff08;生物识别扫描器的存在增加了冒充的难度&#xff09;。如果…

第19章-IPv6基础

1. IPv4的缺陷 2. IPv6的优势 3. 地址格式 3.1 格式 3.2 长度 4. 地址书写压缩 4.1 段内前导0压缩 4.2 全0段压缩 4.3 例子1 4.4 例子 5. 网段划分 5.1 前缀 5.2 接口标识符 5.3 前缀长度 5.4 地址规模分类 6. 地址分类 6.1 单播地址 6.2 组播地址 6.3 任播地址 6.4 例子 …

ICLR/NeurIPS论文分享:任务通用的时序基础模型

吴海旭 清华大学软件学院博士生 师从龙明盛副教授&#xff0c;研究方向为深度学习及其在复杂时空物理过程建模中的应用&#xff0c;目前在Nature Machine Intelligence、IEEE TPAMI、ICML、NeurIPS上发表多篇论文&#xff0c;研究成果在中国气象局、北京冬奥会落地应用。曾获清…

Linux信号【systemV】

目录 前言 正文&#xff1a; 1消息队列 1.1什么是消息队列&#xff1f; 1.2消息队列的数据结构 1.3消息队列的相关接口 1.3.1创建 1.3.2释放 1.3.3发送 1.3.4接收 1.4消息队列补充 2.信号量 2.1什么是信号量 2.2互斥相关概念 2.3信号量的数据结构 2.4…

【高阶数据结构】LRUCache

文章目录 1. 什么是LRU Cache2. LRU Cache的实现3. LinkedHashMap4. LRU Cache OJ题4.1 题目要求4.2 解题思路4.3 代码实现4.3.1 Java代码一4.3.2 Java代码二 1. 什么是LRU Cache LRUCache&#xff0c;全称为Least Recently Used Cache&#xff0c;即最近最少使用缓存&#xf…

基于springboot+vue的纺织品企业财务管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

mac 安装hbuilderx

下载 HBuilderX下载地址: 下载地址 选额mac版本点击下载 安装 如图&#xff0c;将HBuilderX拖到Applications&#xff0c;才是正确的安装姿势。 MacOSX&#xff0c;软件必须安装到/Applications目录&#xff0c;如未安装到此目录&#xff0c;可能会出现插件安装失败、项目创建…

揭秘Java性能调优的层次 | 综合多方向提升应用程序性能与系统高可用的关键(架构层次规划)

揭秘性能调优的层次 | 综合多方向提升应用程序性能与系统的高可用 前言介绍调优层次调优 — 设计案例说明 - 操作轮询控制事件驱动 调优 — 代码案例说明 - ArrayList和LinkedList性能对比案例说明 - 文件读写实现方式的性能对比 调优 — JVMJVM架构分布JVM调优方向**JVM垃圾回…

Linux搭建SFTP服务器

案例&#xff1a;搭建SFTP服务器 SFTP&#xff08;SSH文件传输协议&#xff09; SFTP&#xff08;SSH文件传输协议&#xff09;是一种安全的文件传输协议&#xff0c;用于在计算机之间传输文件。它基于SSH&#xff08;安全外壳协议&#xff09;的子系统&#xff0c;提供了加密的…

EchoServer回显服务器简单测试

目录 工具介绍 工具使用 测试结果 工具介绍 github的一个开源项目,是一个测压工具 EZLippi/WebBench: Webbench是Radim Kolar在1997年写的一个在linux下使用的非常简单的网站压测工具。它使用fork()模拟多个客户端同时访问我们设定的URL&#xff0c;测试网站在压力下工作的…