常见查找算法Java实现

  • 顺序(线性)查找
  • 二分查找/折半查找
  • 插值查找
  • 斐波那契查找

线性查找

判断数列是否包含要求,如果找到了,就提示找到了,并给出下标值

// 线性查找
public static ArrayList<Integer> seqSearch(int[] arr, int value) {ArrayList<Integer> list = new ArrayList<>();for (int i = 0; i < arr.length; i++) {if (value == arr[i]) {list.add(i);}}return list;
}

二分查找

需要对一个有序数组进行二分查找 {1, 8, 10, 89, 1000, 1234},输入一个数
看看该数组是否存在此数,并且求出下标,如果没有就提示”没有这个数”。

思路

  1. 确定该数组的中间的下标

    可以向下取整,也可以向上取整。e.g:4.5向上取整为 5;向下去整为4,此处演示为向下取整
    

    mid=(left+right)/2

  2. 让需要查找的数findVal和arr[mid]比较

    • findVal>arr[mid,说明你要查找的数在mid的右边,因此需要递归的向右查找
    • findVal<arr[mid],说明你要查找的数在mid的左边,因此需要递归的向左查找
    • findVal==arr[mid说明找到,就返回
  3. 递归结束

    • 找到就结束递归
    • 递归完整个数组,仍然没有找到findVal,也需要结束递归当Ieft>right就需要退出
/**
* 二分查找 ---要求数组为有序数组
* @param arr 需要查询的数组
* @param left 数组的最左侧下标
* @param right 数组的最右侧下标
* @param findVal 需要查询的值
* @return
*/
public static int binarySearch(int[] arr, int left, int right, int findVal) {// 当 left > right 时,整个数组遍历后并未找到值if (left > right) {return -1;}int mid = (left + right) / 2;int midVal = arr[mid];if (findVal > midVal) {// 右递归return binarySearch(arr, mid + 1, right, findVal);} else if (findVal < midVal) { // 向左递归return binarySearch(arr, left, mid - 1, findVal);} else {return mid;}
}

二分优化—多索引返回

// 二分查找 ---要求数组为有序数组
public static ArrayList<Integer> binarySearch(int[] arr, int left, int right, int findVal) {// 当 left > right 时,整个数组遍历后并未找到值if (left > right) {return new ArrayList<Integer>();}int mid = (left + right) / 2;int midVal = arr[mid];if (findVal > midVal) {// 右递归return binarySearch(arr, mid + 1, right, findVal);} else if (findVal < midVal) { // 向左递归return binarySearch(arr, left, mid - 1, findVal);} else {// 找到值ArrayList<Integer> resIndexList = new ArrayList<>();// 向 mid 的左右两边扫描
//            int temp = mid - 1;
//            while (true) {// 向左
//                if (temp < 0 || arr[temp] != findVal) {// 退出
//                    break;
//                }
//                // 否则,就temp 放入到resIndexList
//                resIndexList.add(temp);
//                temp -= 1; // temp左移
//            }
//            resIndexList.add(mid); // 将中间索引加入
//
//            temp = mid + 1;
//            while (true) {// 向右
//                if (temp > arr.length - 1 || arr[temp] != findVal) {// 退出
//                    break;
//                }
//                // 否则,就temp 放入到resIndexList
//                resIndexList.add(temp);
//                temp += 1; // temp右移
//            }// 再优化resIndexList.add(mid); // 将中间索引加入for (int i = mid - 1; i >= 0; i--) {// 向左if (arr[i] != findVal) {break;}resIndexList.add(i);}for (int i = mid + 1; i <= arr.length - 1; i++) {// 向右if (arr[i] != findVal) {break;}resIndexList.add(i);}return resIndexList;}
}

插值查找

需要数组是有序,效率比二分查找更高效

  • 插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找。

  • 将折半查找中的求mid索引的公式,low表示左边索引,high表示右边索引right

  • m i d = l o w + h i g h 2 = l o w + 1 2 ( h i g h − l o w ) mid=\frac{low+high}{2}=low+\frac{1}{2}(high-low) mid=2low+high=low+21(highlow) ➡️ m i d = l o w + k e y − a [ l o w ] a [ h i g h ] − a [ l o w ] ( h i g h − l o w ) mid=low+\frac{key-a[low]}{a[high]-a[low]}(high-low) mid=low+a[high]a[low]keya[low](highlow) 【其中key为需要查找的值】

  • 公式优化:int m i d I n d e x = l o w + ( h i g h − l o w ) ∗ ( k e y − a r r [ l o w ] ) / ( a r r [ h i g h ] − a r r [ l o w ] ) ; midIndex=low+(high-low)*(key-arr[low])/(arr[high]-arr[low]); midIndex=low+(highlow)(keyarr[low])/(arr[high]arr[low]);

// 插值查找 ---要求数组为有序数组
// 其中key为需要查找的值
public static int insertValueSearch(int[] arr, int left, int right, int key) {// 注意:key < arr[0] || key > arr[arr.length - 1]必须要有(优化作用),否则可能会造成midIndex越界if (left > right || key < arr[0] || key > arr[arr.length - 1]) {return -1;}int midIndex = left + (right - left) * (key - arr[left]) / (arr[right] - arr[left]);int midVal = arr[midIndex];if (key > midVal) {// 向右扫描递归return insertValueSearch(arr, midIndex + 1, right, key);} else if (key < midVal) {// 向左扫描递归return insertValueSearch(arr, left, midIndex - 1, key);} else {return midIndex;}}
总结
  • 对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找,速度较快
  • 关键字分布不均匀的情况下,该方法不一定比折半查找要好

斐波那契查找(黄金分割法)

需要数组是有序

  • 黄金分割点是指把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割,也称为中外比。这是一个神奇的数字,会带来意向不大的效果。
  • 斐波那契数列{1,1,2,3,5,8,13,21,34,55}发现斐波那契数列的两个相邻数的比例,无限接近黄金分割值0.618

原理

在这里插入图片描述

斐波那契查找原理与前两种相似,仅仅改变了中间结点(mid)的位置,mid不再是中间或插值得到,而是位于黄金分割点附近,即 m i d = l o w + F ( k − 1 ) − 1 mid=low+F(k-1)-1 mid=low+F(k1)1 (F代表斐波那契数列。k代表斐波那契个数)

对F(k-1)-1的理解:

  • 由斐波那契数列 F [ K ] = F [ k − 1 ] + F [ k − 2 ] F[K]=F[k-1]+F[k-2] F[K]=F[k1]+F[k2]的性质,可以得到 ( F [ k ] − 1 ) = ( F [ k − 1 ] − 1 ) + ( F [ k − 2 ] − 1 ) + 1 (F[k]-1)=(F[k-1]-1)+(F[k-2]-1)+1 (F[k]1)=(F[k1]1)+(F[k2]1)+1
    该式说明:只要顺序表的长度为 F [ k ] − 1 F[k]-1 F[k]1,则可以将该表分成长度为 F [ k − 1 ] − 1 F[k-1]-1 F[k1]1 F [ k − 2 ] − 1 F[k-2]-1 F[k2]1的两段,从而中间位置为 m i d = l o w + F ( k − 1 ) − 1 mid=low+F(k-1)-1 mid=low+F(k1)1

  • 类似的,每一子段也可以用相同的方式分割

  • 但顺序表长度 n n n不一定刚好等于 F [ K ] − 1 F[K]-1 F[K]1,所以需要将原来的顺序表长度n增加至 F [ K ] − 1 F[K]-1 F[K]1。这里的 k k k值只要能使得 F [ k ] − 1 F[k]-1 F[k]1恰好大于或等于 n n n即可,由以下代码得到,顺序表长度增加后,新增的位置(从 n + 1 n+1 n+1 F [ K ] − 1 F[K]-1 F[K]1位置),都赋为 n n n位置的值即可。

    while (high > f[k] - 1) {// 如果大于,则k++k++;
    }
    

注意:因为黄金分割点是第三段的前一段除以整段,之所以减1是因为数组是从0开始,所以 F [ k ] − 1 = ( F [ k − 1 ] − 1 ) + ( F [ k − 2 ] − 1 ) + 分割点 F[k]-1=(F[k-1]-1)+(F[k-2]-1)+分割点 F[k]1=(F[k1]1)+(F[k2]1)+分割点,第三点,由于f(k) 有可能小于n(也就是high),就不满足斐波那契数列要求

// 使用非递归方法得到一个斐波那契数列
public static int maxSize = 20;// 后面需要mid=low+F(k-1)-1,因此先获取一个斐波那契数列
public static int[] fib() {int[] f = new int[maxSize];f[0] = 1;f[1] = 1;for (int i = 2; i < maxSize; i++) {f[i] = f[i - 1] + f[i - 2];}return f;
}// 斐波那契查找 --- 非递归
// key为需要查找的关键码(值)
public static int fibSearch(int[] a, int key) {int low = 0;int high = a.length - 1;int k = 0; // 表示斐波那契分割数值的下标int mid = 0; // 存放a数组分割点int[] f = fib(); // 获取到斐波那契数列// 获取到斐波那契分割数值的下标// f[k] - 1 为临时数组的长度,不得小于a数组的长度while (high > f[k] - 1) {// 如果大于,则k++k++;}// f[k] 可能大于a 的长度,因此需要使用Arrays类构造一个新的数组,并指向temp[]// 不足的部分会使用0填充int[] temp = Arrays.copyOf(a, f[k]);// 实际上需要使用a数组的数填充temp// temp = {1, 8, 10, 80, 1000, 0, 0, 0} => {1, 8, 10, 80, 1000, 1000, 1000, 1000}for (int i = high + 1; i < temp.length; i++) {temp[i] = a[high];}// 使用while 来循环处理找到我们的数keywhile (low <= high) {mid = low + f[k - 1] - 1;if (key < temp[mid]) {// 向左边查找high = mid - 1;// f[k] = f[k-1] + f[k-2],之后f[k-1]继续拆分,因此k--k--;} else if (key > temp[mid]) { // 向右查找low = mid + 1;// f[k] = f[k-1] + f[k-2],之后f[k-2]继续拆分// f[k-1] = f[k-3] + f[k-4],因此k -=2k -= 2;} else {// 找到if (mid <= high) {return mid;} else {return high;}}}return -1;
}

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

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

相关文章

动态规划课堂3-----简单多状态问题(买卖股票最佳时机)

目录 引入&#xff1a; 例题1&#xff1a;按摩师&#xff08;打家劫舍I&#xff09; 例题2&#xff1a;打家劫舍II 例题3&#xff1a;删除并获得点数 例题4&#xff1a;粉刷房子 例题5&#xff1a;买卖股票的最佳时机含冷冻 结语&#xff1a; 引入&#xff1a; 相信看到…

深度学习 精选笔记(8)梯度消失和梯度爆炸

学习参考&#xff1a; 动手学深度学习2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、请联系侵删。 ②已写完的笔记文章会不定时一直修订修改(删、改、增)&#xff0c;以达到集多方教程的精华于一文的目的。 ③非常推荐上面&#xff08;学习参考&#x…

带你快速初步了解Python列表

1.列表 列表主要是用来存储多个数据&#xff0c;是有序的集合 2.创建列表 """ 语法&#xff1a;变量名 [数据1,数据2,数据3......] 注意&#xff1a;列表中的数据类型可以是各种不同的数据类型 """ 创建空列表 list1 [] print(list1) …

Gitlab: 私有化部署

目录 1. 说明 2. 资源要求 3. 安装 4. 配置实践 4.1 服务器 4.2 人员与项目 4.2 部署准备 4.2.1 访问变量及用户账号设置 4.2.2 Runner设置 4.2.3 要点 5. 应用项目 CI/CD 6. 参考 1. 说明 gitlab是一个强大且免费的代码管理/部署工具&#xff0c;能统一集成代码仓…

Freesia项目目录结构

目录结构 前端目录&#xff1a; &#xff08;目录结构来自layui-vue-admin&#xff09; src文件下 api&#xff08;前端请求后端服务的路由&#xff09;assert&#xff08;一些内置或必要的资源文件&#xff09;layouts&#xff08;全局框架样式组件&#xff09;router&…

【转载】深度学习笔记——详解损失函数

原文链接: https://blog.csdn.net/weixin_53765658/article/details/136360033 CSDN账号: Purepisces github账号: purepisces 希望大家可以Star Machine Learning Blog https://github.com/purepisces/Wenqing-Machine_Learning_Blog 损失函数 根据您使用的神经网络类型和数…

第四十七回 一丈青单捉王矮虎 宋公明二打祝家庄-强大而灵活的python装饰器

四面全是埋伏&#xff0c;宋江和众人一直绕圈跑不出去。正在慌乱之时&#xff0c;石秀及时赶到&#xff0c;教大家碰到白杨树就转弯走。走了一段时间&#xff0c;发现围的人越来越多&#xff0c;原来祝家庄以灯笼指挥号令。花荣一箭射下来红灯龙&#xff0c;伏兵自己就乱起来了…

Northwestern University-844计算机科学与技术/软件工程-复试注意事项【考研复习】

本文提到的西北大学是位于密歇根湖泊畔的西北大学。西北大学&#xff08;英语&#xff1a;Northwestern University&#xff0c;简称&#xff1a;NU&#xff09;是美国的一所著名私立研究型大学。它由九人于1851年创立&#xff0c;目标是建立一所为西北领地地区的人服务的大学。…

【力扣白嫖日记】550.游戏玩法分析IV

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 550.游戏玩法分析IV 表&#xff1a;Activity 列名类型player_idintdevice_idintevent_datedategames_played…

从 iOS 设备恢复数据的 20 个iOS 数据恢复工具

作为 iPhone、iPad 或 iPod 用户&#xff0c;您可能普遍担心自己可能会丢失存储在珍贵 iOS 设备中的所有宝贵数据。数据丢失的原因多种多样&#xff0c;这里列出了一些常见原因&#xff1a; 1. iOS 软件更新 2. 恢复出厂设置 3. 越狱 4. 误操作删除数据 5. iOS 设备崩溃 …

C++笔记(五)--- 虚函数(virtual)

目录 虚函数介绍 虚函数、覆盖和重载区别 虚函数介绍 C的虚函数是多态性的表现 1.构造函数不能为虚函数2.子类继承时虚函数仍为虚函数3.虚函数类外实现时&#xff0c;不需要加virtual4.有虚函数的类&#xff0c;析构函数一定要写成虚函数&#xff08;否则可能会造成内存泄漏&…

【代码随想录python笔记整理】第十六课 · 出现频率最高的字母

前言:本笔记仅仅只是对内容的整理和自行消化,并不是完整内容,如有侵权,联系立删。 一、哈希表初步 在之前的学习中,我们使用数组、字符串、链表等等,假如需要找到某个节点,则都要从头开始,逐一比较,直到找到为止。为了能够直接通过要查找的记录找到其存储位置,我们选…

、JMETER与它的组件们

os进程取样器 这个取样器可以让jmeter直接调用python写的测试数据 这样就可以调用python写的测试数据给到jmeter进行调用 注意&#xff1a;1建议python返回转json格式dumps一下&#xff1b;2py文件中需要把结果打印出来&#xff0c;可以不用函数直接编写 传到jmeter之后可以用…

你真的了解C语言中的【柔性数组】吗~

柔性数组 1. 什么是柔性数组2. 柔性数组的特点3. 柔性数组的使用4. 柔性数组的优势 1. 什么是柔性数组 也许你从来没有听说过柔性数组这个概念&#xff0c;但是它确实是存在的。 C99中&#xff0c;结构体中的最后⼀个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员…

MyBatis 学习(五)之 高级映射

目录 1 association 和 collection 介绍 2 案例分析 3 一对一关联和一对多关联 4 参考文档 1 association 和 collection 介绍 在之前的 SQL 映射文件中提及了 resultMap 元素的 association 和 collection 标签&#xff0c;这两个标签是用来关联查询的&#xff0c;它们的属…

算法--时空复杂度分析以及各个数据量对应的可使用的算法(C++;1s内)

这里写目录标题 由数据范围反推算法时间复杂度以及算法内容分析时间复杂度看循环实例1实例2 固定时间复杂度快排和归并排序二分高精度算法双指针算法单链表插入删除操作栈和队列的操作单调栈和单调队列KMPTire并查集堆哈希表BFS、DFS图的深度优先、宽度优先遍历dijkstra算法朴素…

瑞_Redis_Redis的Java客户端

文章目录 1 Redis的Java客户端1.1 Jedis快速入门1.1.1 入门案例1.1.1.1 项目构建1.1.1.2 引入依赖1.1.1.3 建立连接1.1.1.4 释放资源1.1.1.5 测试1.1.1.6 完整测试类代码 1.1.2 Jedis连接池1.1.2.1 连接池工具类1.1.2.2 改造原始代码 &#x1f64a; 前言&#xff1a;本文章为瑞…

常用sql语句及其优化

文章目录 介绍常用sql语句1. 数据查询1.1 SELECT 语句1.2 DISTINCT 关键字1.3 WHERE 子句1.4 ORDER BY 子句1.5 LIMIT 关键字 2. 数据更新2.1 INSERT INTO 语句2.2 UPDATE 语句2.3 DELETE FROM 语句 3. 数据管理3.1 CREATE TABLE 语句3.2 ALTER TABLE 语句3.3 DROP TABLE 语句 …

批量自动加好友神器!微信快速扩友秘籍!

对于一些个人或者企业来说&#xff0c;传统的人工添加好友方式往往会出现效率低下&#xff0c;费时费力的问题。那么&#xff0c;有没有一种快速、便捷、安全的方式来解决这个问题呢&#xff1f;答案当然是肯定的&#xff0c;那就是通过使用微信管理系统来解决这一问题。 在微…

基于java+springboot景区行李寄存管理系统设计和实现

基于javaspringboot景区行李寄存管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取…