查找算法——java

 顺序查找(顺序表查找) 

顺序查找也称为线形查找,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结    点关键字与给定值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 的长度不等时,采用这种方法比较合适。

查找总结:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

web自动化笔记十:UnitTest基本使用

一、UnitTest框架 ①、什么是框架&#xff1f; 1、框架英文单词framework 2、为解决一类事情的功能集合 ②、为什么使用UnitTest框架 1、批量执行用例 2、提供丰富的断言知识 3、可以…

应用稳定性优化2:Crash/Tombstone问题分析及定位

1. Crash/Tombstone问题原因分析 2. Tombstone问题定位方法 本节主要讲解Tombstone问题的分析定位方法。 2.1 信号量分析法 信号机制是进程之间相互传递消息的一种方法&#xff0c;下表展示的是一些常见的信号种类。 SIGBUS与SIGSEGV的区别 SIGBUS(Bus error)意味着指针所…

Javaweb之SpringBootWeb案例之自动配置的两种常见方案的详细解析

3.2.2.2 方案一 ComponentScan组件扫描 SpringBootApplication ComponentScan({"com.itheima","com.example"}) //指定要扫描的包 public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(Sprin…

【贪心算法】121. 买卖股票的最佳时机 I Leetcode 122. 买卖股票的最佳时机 II

【贪心算法】121. 买卖股票的最佳时机 I Leetcode 122. 买卖股票的最佳时机 II 121. 买卖股票的最佳时机 I贪心算法&#xff1a;遍历每一天卖出金额&#xff0c;一边计算卖出金额减之前的最小值&#xff0c;一边更新该卖出day前的最小金额 122. 买卖股票的最佳时机 II贪心算法…

Springboot+vue的商业辅助决策系统的设计与实现(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的商业辅助决策系统的设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的商业辅助决策系统的设计与实现&#xff0c;采…

C++ //练习 10.17 重写10.3.1节练习10.12(第345页)的程序,在对sort的调用中使用lambda来代替函数compareIsbn。

C Primer&#xff08;第5版&#xff09; 练习 10.17 练习 10.17 重写10.3.1节练习10.12&#xff08;第345页&#xff09;的程序&#xff0c;在对sort的调用中使用lambda来代替函数compareIsbn。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xf…

数据库原理(一)

1、基本概念 学号姓名性别出生年月籍贯220101张三男2003江苏220102李四男2003山东220103王五女2003河北220104赵六女2003天津220105张四男2003北京220106李五女2003江苏220107王六女2003山东220108张七男2003河北220109张九男2003天津220110李十女2003北京 1.1数据&#xff0…

《系统架构设计师教程(第2版)》第5章-软件工程基础知识-05-净室软件工程(CSE)

文章目录 1. 概述2. 理论基础2.1 函数理论2.2 抽样理论 3. 技术手段3.1 增量式开发3.2 基于函数的规范与设计3.3 正确性验证3.4 统计测试 (Statistically Based Testing) 和软件认证 4. 应用与缺点1&#xff09;太理论化2&#xff09;缺少传统模块测试3&#xff09;带有传统软件…

频率域采样

1. 频率域采样 (1) 采样的过程&#xff1a;DFT的X(k)是对周期且连续的频谱X()在[0,2pi)上的等间隔采样&#xff0c;采N个点得到的&#xff0c;采样间隔是&#xff1b;频域采样要求时域有限&#xff0c;即假设x(n)的长度是有限值M&#xff0c;x(n)的SFT是X()。 (2) X(k) 做IDF…

YOLOv9有效提点|加入BiFormer、SEA、EMA、Efficient se等几十种注意力机制(三)

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文只有代码及注意力模块简介&#xff0c;YOLOv9中的添加教程&#xff1a;可以看这篇文章。 YOLOv9有效提点|加入SE、CBAM、ECA、SimA…

svn介绍 4.0

一、svn介绍&#xff08;版本控制工具&#xff09; 1、svn的定义&#xff1a; svn是一个开放源代码的版本控制系统&#xff0c;通过采用分支管理系统的高效管理&#xff0c;简而言之就是用于多个人共同开发同一个项目&#xff0c;实现共享资源&#xff0c;实现最终集中式个管…

全球十大正规伦敦金交易平台app软件最新排名(综合版)

伦敦金作为当前国际市场中较为成熟、灵活的投资产品自然备受青睐&#xff0c;但投资者在选择交易软件时&#xff0c;应该尽量选择在行业内排名较高&#xff0c;口碑较好的平台&#xff0c;这样才能获得可靠的投资服务。刚开始不太懂得如何选择伦敦金软件的时候&#xff0c;投资…

Carla自动驾驶仿真九:车辆变道路径规划

文章目录 前言一、关键函数二、完整代码效果 前言 本文介绍一种在carla中比较简单的变道路径规划方法&#xff0c;主要核心是调用carla的GlobalRoutePlanner模块和PID控制模块实现变道&#xff0c;大体的框架如下图所示。 一、关键函数 1、get_spawn_point(),该函数根据指定r…

如何查看docker容器里面运行的nginx的配置文件哪

要查看Docker容器内运行的Nginx配置文件的位置&#xff0c;你可以通过进入容器的shell环境来直接查看。Nginx的默认配置文件通常位于/etc/nginx/nginx.conf&#xff0c;而网站特定的配置文件通常位于/etc/nginx/conf.d/目录中。以下是步骤来查看这些配置文件&#xff1a; 步骤…

【嵌入式学习】网络编程day0229

一、思维导图 二、练习 TCP通信 服务器 #include <myhead.h> #define SER_IP "192.168.126.42" #define SER_PORT 8888 int main(int argc, const char *argv[]) {int wfd-1;//创建套接字if((wfdsocket(AF_INET,SOCK_STREAM,0))-1){perror("error"…

基于CNN-LSTM-Attention的时间序列回归预测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1卷积神经网络&#xff08;CNN&#xff09;在时间序列中的应用 4.2 长短时记忆网络&#xff08;LSTM&#xff09;处理序列依赖关系 4.3 注意力机制&#xff08;Attention&#xff09; 5…

探索数据结构:深入了解顺序表的奥秘

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 贝蒂的主页&#xff1a;Betty’s blog 1. 什么是顺序表 顺序表是用一段物理地址连续的存储单元依次存储数据元…

迪杰斯特拉算法的具体应用

fill与memset的区别介绍 例一 #include <iostream> #include <algorithm> using namespace std; const int maxn500; const int INF1000000000; bool isin[maxn]{false}; int G[maxn][maxn]; int path[maxn],rescue[maxn],num[maxn]; int weight[maxn]; int cityn…

011 Linux_线程概念与创建

前言 本文将会向你介绍线程的概念&#xff0c;以及线程是怎么被创建的 线程概念 一、进程是承担系统资源的基本实体&#xff0c;线程是cpu调度的基本单位 首先&#xff0c;地址空间在逻辑上相当于进程的资源窗口&#xff0c; 每个进程都有这样一个资源窗口。通过地址空间页…

《热辣滚烫》:用坚持不懈开启逆境中的职场出路

"你只活一次&#xff0c;所以被嘲笑也没有关系&#xff0c;想哭也没有关系&#xff0c;失败更没有关系。" “人生就像一场拳击赛&#xff0c;你站不起来&#xff0c;就永远不知道自己有多强” “命运只负责洗牌&#xff0c;出牌的永远是自己。” 在今年的贺岁档电影市…