二分查找的5种实现--Java版

这篇具有很好参考价值的文章主要介绍了二分查找的5种实现--Java版。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


云仔☁笔记

1. 基础版

左闭右闭

public static int binaryBasic(int[] arr, int target) {
        int i = 0, j = arr.length - 1;

        while (i <= j) {
            int m = (j + i)>>>1; //一半取整
            if (arr[m] < target) {//目标在右边
                i = m + 1;
            }else if (target < arr[m]) {//目标在左边
                j = m - 1;
            }else {//找到结果
                return m;
            }
        }
    	//找不到,则返回-1
        return -1;
    }

2. 改动版

 public static int binaryAlter(int[] arr, int target) {
        int i = 0, j = arr.length; //改动1

        while (i < j) {  //改动2
            int m = (j + i)>>>1;
            if (arr[m] < target) {
                i = m + 1;
            }else if (target < arr[m]) {
                j = m;     //改动3
            }else {//找到结果
                return m;
            }
        }

        return -1;
    }
  • 左闭右开,即 j 只是一个边界,不可能等于目标元素
时间复杂度
最坏情况

循环次数 L = f l o o r ( l o g 2 ( n ) + 1 ) ∗ 5 + 4 L = floor(log_2(n) + 1) * 5 + 4 L=floor(log2(n)+1)5+4

次数
i < j L + 1
int m = (j + i)>>>1; L
arr[m] < target L
target < arr[m] L
i = m + 1 L
  • 最终表达式 : f l o o r ( l o g 2 ( n ) + 1 ) ∗ 5 + 4 floor(log_2(n) + 1) * 5 + 4 floor(log2(n)+1)5+4
  • 渐进上界: O ( l o g 2 ( n ) ) O(log_2(n)) O(log2(n))
最好的情况

若待查找元素恰好在数组中央,只需要循环一次 O ( 1 ) O(1) O(1)

空间复杂度
  • 需要常数个指针i,j,m,因此额外占用的空间是 O ( 1 ) O(1) O(1)

3. 平衡版

public static int binaryBalance(int[] arr, int target) {
        int i = 0, j = arr.length;

        while (1 < j - i) {
            int m = (i + j) >>> 1;
            if (target < arr[m]) { //左侧
                j = m;
            }else {
                i = m;
            }
        }

        if (arr[i] == target) {
            return i;
        }else {
            return -1;
        }
    }
  • 左闭右开的区间,i指向的可能是目标,而j指向的不是目标
  • 不在循环内找出,等范围内只剩i时,退出循环,在循环外比较a[i]和target
  • 与改动版相比较
    • 优点:循环内的平均比较次数减少了
    • 缺点:当target恰好在中间时,还是必须执行完循环
时间复杂度

Θ ( l o g ( n ) ) Θ (log(n)) Θ(log(n))

4. 在java中的实现

java.util.Arrays.binarySearch()

    public static int binarySearch(int[] a, int key) {
        return binarySearch0(a, 0, a.length, key);
    }
    private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                     int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }
  • 可以看到java8,使用的咱们前面的基础版实现二分查找,但最终的返回结果是 -(插入索引 + 1),

    源文档中对返回值的描述:

    index of the search key, if it is contained in the array within the specified range; otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which the key would be inserted into the array: the index of the first element in the range greater than the key, or toIndex if all elements in the range are less than the specified key. Note that this guarantees that the return value will be >= 0 if and only if the key is found.

    翻译:如果搜索键包含在指定范围内的数组中,则搜索键的索引;否则,(-(插入点)- 1)。插入点定义为键插入数组的点:范围内第一个大于键的元素的索引,如果范围内所有元素都小于指定的键,则为toIndex。注意,这保证了当且仅当找到键时返回值将>= 0。

思考: 为什么要+1呢?

若不 + 1,当插入位置在数组的最前端时,得到的结果时 -0,在java中无法区分-0和0,所通过 + 1 的操作,避免了在这个问题

扩展
  • 得到插入索引后,可以将目标值插入

  • 我们来实现这个过程,在java中数据的长度是不可变的,所以我们需要通过创建一个新的数组来实现这个过程文章来源地址https://www.toymoban.com/news/detail-850026.html

        //定义测试数据
        int[] arr = {5,6,7,12,45,67,89,95,99,102};
        int target = 42;
        //进行二分查找
        int i = Arrays.binarySearch(arr, target);
        System.out.println(i);
        if (i < 0) {
            //得到索引
            int insertIndex = Math.abs(i + 1);
            //创建新的数组,接收插入后的数据
            int[] b = new int[arr.length + 1];
            //使用java中的数据复制方法
            System.arraycopy(arr, 0, b, 0, insertIndex);
            b[insertIndex] = target;
            System.arraycopy(arr, insertIndex, b, insertIndex + 1, arr.length - insertIndex);
            //打印结果
            System.out.println(Arrays.toString(b));
        }

5. 对重复元素的处理

5.1 最左 leftMost
    /**
     * 最左查询
     * @param arr 查询数组
     * @param target 目标
     * @return 若存在,返回最左索引,若不存在,返回 -(比目标值大值的最左索引+1)
     */
    public static int leftMost(int[] arr, int target) {
        int i = 0, j = arr.length - 1;
        while (i <= j) {
            int m = (j + i)>>>1;
            if (target <= arr[m]) {
                j = m - 1;
            }else {
                i = m + 1;
            }
        }

        return i < arr.length && arr[i] == target ? i : -(i + 1);
    }
5.2 最右rightMost
    /**
     * 最右
     * @param arr 查询数组
     * @param target 目标
     * @return 若存在,返回最右索引,若不存在,返回 -(比目标值小的值的最右索引 + 1)
     */
    public static int rightMost(int[] arr, int target) {
        int i = 0, j = arr.length - 1;
        while (i <= j) {
            int m = (j + i)>>>1;
            if (target < arr[m]) {
                j = m - 1;
            }else {
                i = m + 1;
            }
        }

        return i > 0 && i <= arr.length && arr[i - 1] == target ? i - 1 : - (i + 1);
    }

6. 力扣题型练习

  • 34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
  • 35. 搜索插入位置 - 力扣(LeetCode)
  • 704. 二分查找 - 力扣(LeetCode)

到了这里,关于二分查找的5种实现--Java版的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构,查找算法(二分,分块,哈希)

    一、查找算法         1、二分查找:(前提条件: 必须有序的序列) 2、分块查找:(块间有序,块内无序)     索引表  +  源数据表     思路:     (1)先在索引表中确定在哪一块中     (2)再遍历这一块进行查找 //索引表 typedef  struct  {     int max; //块中最大值

    2024年02月11日
    浏览(56)
  • 数据结构和算法之二分法查找

    二分法查找,也称作 二分查找 或 折半查找 ,是一种在有序数组中快速查找特定元素的算法。它采用分治法思想,通过将问题划分为规模更小的子问题,并且通过对子问题的查找来解决原问题。 二分法查找的思路是不断地将数组一分为二,然后判断目标值在哪一部分,进而

    2024年02月09日
    浏览(45)
  • Python数据结构与算法篇(五)-- 二分查找与二分答案

    1.1 定义         二分查找又称折半查找、二分搜索、折半搜索等,是一种在静态查找表中查找特定元素的算法。         所谓静态查找表,即只能对表内的元素做查找和读取操作,不允许插入或删除元素。         使用二分查找算法,必须保证查找表中存放的是有

    2023年04月20日
    浏览(45)
  • 数据结构-查找(顺序查找与二分查找的讲解与代码实现)

    顺序查找概念:从表的另一端开始,一次将记录的和给定值进行比较,若某个记录的和给定的值相等,则查找成功,反之则查找失败。 ASL:平均查找长度 pi查找概率,ci查找次数 eg:序列1,2,3 查找1的次数为1概率为1/3,2为两次概率1/3,3的次数为3概率1/3  将12

    2024年02月06日
    浏览(68)
  • 数据结构——用Java实现二分搜索树

    目录 一、树 二、二分搜索树 1.二叉树 2.二分搜索树 三、代码实现 1.树的构建 2.获取树中结点的个数 3.添加元素 4.查找元素 (1)查找元素是否存在 (2)查找最小元素 (3)查找最大元素 5.二分搜索树的遍历 (1)前序遍历: (2)中序遍历: (3)后序遍历: (4)层序遍历

    2024年02月19日
    浏览(39)
  • java实现二分查找算法

    递归实现: public static int binarySearchRecursive(int[] arr, int target) {     return binarySearchRecursive(arr, target, 0, arr.length - 1); }   private static int binarySearchRecursive(int[] arr, int target, int low, int high) {     if (low high) {         return -1; // 没有找到目标元素     }          int mid = (low + high) / 2

    2024年04月09日
    浏览(42)
  • Java 语言实现二分查找算法

    【引言】 二分查找算法是一种高效且常用的查找算法。它适用于已排序的数组或列表,并通过将目标值与中间值进行比较,来确定目标值在左侧还是右侧。本文将使用Java语言实现二分查找算法,并详细讲解其思想和代码实现。 【算法思想】 二分查找的核心思想是不断缩小查

    2024年02月11日
    浏览(33)
  • 【手撕数据结构】二分查找(好多细节)

    🌈键盘敲烂,年薪30万🌈 目录 普通版本的二分查找: right只负责控制边界(少了两次比较): 时间复杂度更稳定的版本: BSLeftmost: BSRightmost:   🏸细节1:循环判定条件是left = right ⭐细节2:mid = (left + right ) 1 原因见代码注释 改动1:while条件是left right 改动2:right = nums.len

    2024年02月05日
    浏览(46)
  • 二分搜索树(校招数据结构最低要求版)Java

    二分搜索树(Binary Search Tree,BST)是一种常见的数据结构,它能够高效地存储和查找数据。它的特点是每个节点都包含一个值,并且每个节点的左子树的值都小于节点的值,右子树的值都大于节点的值。 通过这种有序的排列方式,我们可以在二分搜索树中进行高效的查找操作

    2024年02月10日
    浏览(42)
  • 浙大数据结构第一周01-复杂度3 二分查找

    本题要求实现二分查找算法。 函数接口定义: 其中 List 结构定义如下: L 是用户传入的一个线性表,其中 ElementType 元素可以通过、==、进行比较,并且题目保证传入的数据是递增有序的。函数 BinarySearch 要查找 X 在 Data 中的位置,即数组下标(注意:元素从下标1开始存储)

    2024年02月12日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包