二分查找算法

学习笔记:二分查找算法

一、二分查找定义

二分查找(Binary Search)是一种高效的查找算法,它用于在有序数组中快速找到目标元素的位置。相比于线性查找(从头到尾一个一个查找),二分查找利用数组的排序特性,通过逐步缩小查找范围来加速查找过程。

原理

二分查找的核心思想是折半查找。在每次查找时:

  1. 取当前查找范围的中间元素与目标元素进行比较。
  2. 如果目标小于中间元素,则继续在左半部分查找;
  3. 如果目标大于中间元素,则在右半部分查找;
  4. 重复上述步骤,直到找到目标元素,或查找范围为空(即未找到)。

时间复杂度

  • 时间复杂度:O(log n)
    • 每次查找都将查找范围减半,因此时间复杂度为对数级别,远比线性查找 O(n) 快。
  • 空间复杂度:O(1) (如果是非递归实现)

二、二分查找的条件

  1. 数组必须有序:无论升序还是降序,二分查找都依赖于数组的排序。
  2. 目标元素在有序数组中:如果数组无序,二分查找无法正常工作。

三、二分查找的步骤

  1. 定义查找的左右边界,即初始的查找范围。
  2. 计算中间位置 mid
  3. 比较 arr[mid] 与目标元素:
    • 如果 arr[mid] 等于目标,查找成功;
    • 如果 arr[mid] 大于目标,则目标应在左半部分,缩小右边界;
    • 如果 arr[mid] 小于目标,则目标应在右半部分,缩小左边界。
  4. 重复步骤2和3,直到左右边界交错或找到目标。

四、代码实现(Java版)

非递归版

public class BinarySearch {

    public static int binarySearch(int[] arr, int target) {
        int left = 0;
        int right = arr.length - 1;

        while (left <= right) {
            // 取中间位置
            int mid = left + (right - left) / 2;

            // 比较中间值与目标值
            if (arr[mid] == target) {
                return mid; // 找到目标,返回索引
            } else if (arr[mid] < target) {
                left = mid + 1; // 目标在右半部分
            } else {
                right = mid - 1; // 目标在左半部分
            }
        }
        
        return -1; // 未找到目标,返回 -1
    }

    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9, 11, 13, 15}; // 已排序的数组
        int target = 7;

        int result = binarySearch(arr, target);
        
        if (result != -1) {
            System.out.println("目标元素 " + target + " 的索引是: " + result);
        } else {
            System.out.println("目标元素 " + target + " 不存在于数组中。");
        }
    }
}

递归版

public class BinarySearchRecursive {

    public static int binarySearch(int[] arr, int target, int left, int right) {
        if (left > right) {
            return -1; // 查找范围为空,未找到目标
        }

        // 取中间位置
        int mid = left + (right - left) / 2;

        if (arr[mid] == target) {
            return mid; // 找到目标
        } else if (arr[mid] < target) {
            return binarySearch(arr, target, mid + 1, right); // 目标在右半部分
        } else {
            return binarySearch(arr, target, left, mid - 1); // 目标在左半部分
        }
    }

    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9, 11, 13, 15}; // 已排序的数组
        int target = 7;

        int result = binarySearch(arr, target, 0, arr.length - 1);
        
        if (result != -1) {
            System.out.println("目标元素 " + target + " 的索引是: " + result);
        } else {
            System.out.println("目标元素 " + target + " 不存在于数组中。");
        }
    }
}

找出一个数组中元素的起始位和末位

import java.util.Scanner;

public class BinarySearch {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        int[] q = new int[n];
        for (int i = 0; i < n; i++) {
            q[i] = scanner.nextInt();
        }
        while (m-- > 0) {
            int x = scanner.nextInt();
            int l = 0, r = n - 1;
            while (l <= r) {
                int mid = l + (r - l) / 2;
                if (q[mid] >= x) r = mid - 1;
                else l = mid + 1;
            }
            if (l == n || q[l] != x) {
                System.out.println("-1 -1");
            } else {
                System.out.print("1 ");
                int left = 0, right = n - 1;
                while (left <= right) {
                    int mid = left + (right - left) / 2;
                    if (q[mid] <= x) left = mid + 1;
                    else right = mid - 1;
                }
                System.out.println(left);
            }
        }
        scanner.close();
    }
}

五、代码讲解

  1. 非递归版

    • 我们用 while (left <= right) 来控制查找范围。每次迭代时,我们通过调整 leftright 来缩小查找范围,直到找到目标元素或者查找范围为空。
  2. 递归版

    • 递归版与非递归版的逻辑一致,只是通过函数自身的递归调用来缩小查找范围。当递归的左右边界满足 left > right 时,查找结束。

六、二分查找的边界条件

  1. 数组为空:直接返回 -1
  2. 目标不在数组中:经过多次折半查找后,左右边界交错,返回 -1
  3. 数组有重复元素:二分查找通常返回找到的第一个满足条件的元素索引,无法直接处理重复元素的情况。如果需要查找第一个或最后一个重复元素的位置,需要进行额外的处理。

七、总结

二分查找是一种高效的查找算法,特别适合在大规模有序数组中查找目标元素。它的时间复杂度为O(log n),在查找效率上远优于O(n)的线性查找。

通过掌握二分查找的基本原理和多种实现方式(非递归和递归),你可以在日常开发中处理各种查找问题,并为后续深入学习其他高级算法打下良好的基础。#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值