当前位置: 首页 > news >正文

Java 与查找算法(2)二分查找

一、二分查找

二分查找,也称折半查找,是一种常见的查找算法。它的思想是将有序数组分成两部分,取中间位置的值与目标值进行比较,如果相等则返回该位置,如果目标值小于中间值,则在左半部分继续查找,否则在右半部分继续查找,直到找到目标值或者数组被遍历完。

二分查找的时间复杂度为 O(log n),是一种高效的查找算法。但是它要求数组必须是有序的,因此在某些情况下,为了使用二分查找,需要先对数组进行排序。

二分查找的实现有两种方式:

  1. 递归实现

递归实现二分查找的核心思想是将数组不断地分成两半,直到找到目标值或者数组被遍历完。具体实现可以参考以下代码:

int binarySearchRecursive(int arr[], int left, int right, int target) {if (left > right) {return -1;  // 没有找到目标值,返回 -1}int mid = left + (right - left) / 2;  // 计算中间位置if (arr[mid] == target) {return mid;  // 找到目标值,返回位置} else if (arr[mid] > target) {return binarySearchRecursive(arr, left, mid - 1, target);  // 在左半部分继续查找} else {return binarySearchRecursive(arr, mid + 1, right, target);  // 在右半部分继续查找}
}
  1. 非递归实现

非递归实现二分查找的核心思想是使用循环不断地将数组分成两半,直到找到目标值或者数组被遍历完。具体实现可以参考以下代码:

int binarySearchIterative(int arr[], int left, int right, int target) {while (left <= right) {int mid = left + (right - left) / 2;  // 计算中间位置if (arr[mid] == target) {return mid;  // 找到目标值,返回位置} else if (arr[mid] > target) {right = mid - 1;  // 在左半部分继续查找} else {left = mid + 1;  // 在右半部分继续查找}}return -1;  // 没有找到目标值,返回 -1
}

需要注意的是,二分查找只适用于静态数组,即数组不会频繁地进行插入、删除等操作。如果需要频繁地进行这些操作,可以考虑使用其他数据结构,如平衡二叉树、哈希表等。

二、二分查找的性质

二分查找也称为折半查找,是一种在有序数组中查找特定元素的算法。它具有以下性质:

  1. 二分查找要求数组必须是有序的,如果数组无序,则需要先进行排序操作。

  2. 二分查找的时间复杂度为O(log n),其中n为数组的长度。这是一种非常高效的查找算法,适用于大型数据集。

  3. 二分查找只适用于静态数据集,即数据集不会频繁地插入、删除或修改。如果数据集经常变化,则需要使用其他算法。

  4. 二分查找是一种分治算法,它将问题分成两个子问题进行解决。每次比较都可以将搜索范围缩小一半,直到找到目标元素或搜索范围为空。

  5. 二分查找可以使用递归或迭代的方式实现。递归实现代码简单,但可能会导致栈溢出。迭代实现代码稍微复杂一些,但不会出现栈溢出的问题。

  6. 二分查找只能用于查找单个元素,无法用于查找多个元素。如果需要查找多个元素,可以使用二分查找的变体,如二分查找第一个出现的元素、二分查找最后一个出现的元素、二分查找第一个大于等于目标元素的元素、二分查找最后一个小于等于目标元素的元素等。

三、二分查找的变种

除了基本的二分查找外,还有以下几种常见的二分查找变种:

  1. 查找第一个值等于给定值的元素

在基本的二分查找中,当找到目标元素时就返回。但是,如果数组中存在多个值等于目标元素的元素,则基本的二分查找无法确定哪一个是第一个。因此,需要对基本的二分查找进行修改,使其能够查找第一个值等于给定值的元素。

具体实现方式如下:

  • 如果mid指向的元素等于目标元素,判断mid是否为第一个元素或者mid前一个元素不等于目标元素,如果是,则mid就是第一个值等于给定值的元素;否则,继续在左半部分查找。
  • 如果mid指向的元素大于目标元素,则在左半部分查找。
  • 如果mid指向的元素小于目标元素,则在右半部分查找。
  1. 查找最后一个值等于给定值的元素

与查找第一个值等于给定值的元素类似,查找最后一个值等于给定值的元素也需要对基本的二分查找进行修改。

具体实现方式如下:

  • 如果mid指向的元素等于目标元素,判断mid是否为最后一个元素或者mid后一个元素不等于目标元素,如果是,则mid就是最后一个值等于给定值的元素;否则,继续在右半部分查找。
  • 如果mid指向的元素大于目标元素,则在左半部分查找。
  • 如果mid指向的元素小于目标元素,则在右半部分查找。
  1. 查找第一个大于等于给定值的元素

查找第一个大于等于给定值的元素也需要对基本的二分查找进行修改。

具体实现方式如下:

  • 如果mid指向的元素大于等于目标元素,判断mid是否为第一个元素或者mid前一个元素小于目标元素,如果是,则mid就是第一个大于等于给定值的元素;否则,继续在左半部分查找。
  • 如果mid指向的元素小于目标元素,则在右半部分查找。
  1. 查找最后一个小于等于给定值的元素

查找最后一个小于等于给定值的元素也需要对基本的二分查找进行修改。

具体实现方式如下:

  • 如果mid指向的元素小于等于目标元素,判断mid是否为最后一个元素或者mid后一个元素大于目标元素,如果是,则mid就是最后一个小于等于给定值的元素;否则,继续在右半部分查找。
  • 如果mid指向的元素大于目标元素,则在左半部分查找。

四、二分查找的应用场景

二分查找的应用场景包括但不限于以下几个方面:

  1. 查找有序数组中的元素:二分查找是一种高效的查找算法,适用于有序数组中查找特定元素。例如,在一个数值递增的数组中查找某个数值是否存在。

  2. 查找最大值或最小值:如果一个数组是单调递增或递减的,可以使用二分查找来查找最大值或最小值。例如,在一个升序数组中查找最小值,或者在一个降序数组中查找最大值。

  3. 查找数据范围:如果一个数组中的元素满足某种特定的条件,可以使用二分查找来查找数据范围。例如,在一个有序数组中查找某个数值出现的次数,或者在一个升序数组中查找第一个大于等于某个值的元素。

  4. 查找旋转数组中的元素:如果一个数组是旋转有序的,可以使用二分查找来查找特定元素。例如,在一个旋转有序数组中查找某个数值是否存在。

  5. 查找数学函数的零点:如果一个数学函数是单调递增或递减的,可以使用二分查找来查找函数的零点。例如,在一个单调递增的函数中查找函数f(x)=0的解。

二分查找是一种高效的查找算法,适用于有序数组中查找特定元素或查找数据范围。它的时间复杂度为O(log n),适用于大型数据集。

五、二分查找在spring 中的应用

在Spring框架中,二分查找算法主要应用于Bean的查找和排序。Spring的Bean容器是一个包含多个Bean的容器,当需要获取某个Bean时,Spring框架会根据Bean的名称或类型进行查找。在查找时,Spring框架使用二分查找算法来提高查找效率。

Spring框架中的二分查找算法主要应用于以下两个方面:

  1. Bean的查找:Spring框架中的Bean容器是一个Map类型的容器,其中Bean的名称作为Map的Key,Bean实例作为Map的Value。当需要获取某个Bean时,Spring框架会根据Bean的名称或类型进行查找。在查找时,Spring框架使用二分查找算法来提高查找效率。

  2. Bean的排序:Spring框架中的Bean容器可以对Bean进行排序。在排序时,Spring框架使用二分查找算法来查找插入位置,从而提高排序效率。

Spring框架中的二分查找算法主要应用于Bean的查找和排序,可以提高查找和排序的效率。

http://www.lryc.cn/news/90654.html

相关文章:

  • Java程序设计入门教程--原始类与包装类
  • pip安装python库速度慢、失败及超时报错解决办法
  • 向量数据库
  • leetcode 11.盛最多水的容器
  • 都说00后已经躺平了,但是有一说一,该卷的还是卷啊。
  • 牛客网刷题学习SQL(二)
  • 深蓝学院 C++笔记 先导篇章 - 绪论
  • R7-19 天梯赛团队总分
  • 使用 Kotlin 的 Opt-in (选择加入)功能注解API提示当前非稳定API
  • webpack配置排除打包
  • HNU-操作系统OS-ucoreLab系列-感悟
  • MySQL运维篇(三)
  • Lecture 2 Text Preprocessing
  • web练习第二周
  • LC-1439. 有序矩阵中的第 k 个最小数组和(二分答案、多路归并)
  • 一文1000字从0到1实现Jenkins+Allure+Pytest的持续集成
  • 给一个有序数组生成平衡搜索二叉树(java)
  • 【JavaSE】Java基础语法(二十二):包装类
  • javascript基础十八:说说你对JavaScript中事件循环的理解​
  • 详解js中的浅拷贝与深拷贝
  • Day9 敏捷测试——敏捷开发的特征、什么是敏捷测试?、极限编程、极限测试
  • k8s 维护node与驱逐pod
  • SouapUI接口测试之创建性能测试
  • springboot整合kafka入门
  • Rust 笔记:Rust 语言中的字符串
  • 华为OD机试真题 Java 实现【将真分数分解为埃及分数】【牛客练习题】
  • Zemax Lumerical | 二维光栅出瞳扩展系统优化
  • Linux-0.11 文件系统read_write.c详解
  • 什么是用户态和内核态?用户态切换内核态会有什么影响?
  • 探索iOS之CoreImage框架