【算法(三·六):分治思想——二分查找】

算法介绍

二分查找也称为折半查找,是一种用于在有序数据结构(通常是有序数组)中查找特定元素的高效算法。该算法的思想基于分治策略,通过将数据结构分成两半,然后比较目标元素与中间元素的大小关系,从而确定在哪一半继续查找。

算法问题描述

给定一个有序数组(通常是升序排列)以及一个目标元素,目标是确定该元素是否在数组中,如果存在则返回其索引,否则返回 -1。

算法思想

二分查找算法采用分治策略,将数组分成两半,然后通过比较目标元素与中间元素的大小,确定继续查找的方向。如果目标元素等于中间元素,则找到了,返回索引。如果目标元素小于中间元素,则在左半部分查找。如果目标元素大于中间元素,则在右半部分查找。这个过程不断重复,直到找到目标元素或确定它不在数组中。

算法步骤

  • 分(Divide):将给定有序数组分为两半,找到数组的中间元素。
  • 治(Conquer):比较中间元素与目标元素的大小。
    • 如果中间元素等于目标元素,返回中间元素的索引,查找结束。
    • 如果中间元素大于目标元素,说明目标元素可能在左半部分,继续在左半部分递归查找。
    • 如果中间元素小于目标元素,说明目标元素可能在右半部分,继续在右半部分递归查找。
  • 合(Merge):重复上述过程,直到找到目标元素或确定它不在数组中。如果左边界大于右边界,表示目标元素不在数组中,返回 -1。

算法图示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

算法伪代码

递归版本

function binarySearchRecursive(array, target, left, right)
    if left > right
        return -1  # 未找到目标元素
    
    mid = (left + right) / 2  # 计算中间索引

    if array[mid] == target  # 如果中间元素等于目标元素
        return mid  # 返回中间索引,目标元素已找到
    else if array[mid] < target  # 如果中间元素小于目标元素
        return binarySearchRecursive(array, target, mid + 1, right)  # 在右半部分递归查找
    else  # 否则,中间元素大于目标元素
        return binarySearchRecursive(array, target, left, mid - 1)  # 在左半部分递归查找

# 调用二分查找函数
result = binarySearchRecursive(sortedArray, targetElement, 0, length(sortedArray) - 1)

非递归版本

function binarySearch(array, target)
    left = 0             # 初始化左边界为数组的起始索引
    right = length(array) - 1  # 初始化右边界为数组的结束索引
    
    while left <= right  # 当左边界小于等于右边界时循环
        mid = (left + right) / 2  # 计算中间索引
        
        if array[mid] == target  # 如果中间元素等于目标元素
            return mid          # 返回中间索引,目标元素已找到
        else if array[mid] < target  # 如果中间元素小于目标元素
            left = mid + 1         # 更新左边界为 mid + 1,在右半部分查找
        else  # 否则,中间元素大于目标元素
            right = mid - 1        # 更新右边界为 mid - 1,在左半部分查找
    
    return -1  # 循环结束,未找到目标元素,返回 -1 表示不存在

# 调用二分查找函数
result = binarySearch(sortedArray, targetElement)

算法性能

时间复杂度

  • 递归版本的二分查找在每次递归中将搜索范围缩小一半,因此具有 O(log n) 的时间复杂度,其中 n 是数组的大小。这使得它成为一种高效的查找算法。
  • 非递归版本的二分查找同样具有 O(log n) 的时间复杂度,其中 n 是数组的大小。它以相同的效率快速查找目标元素。
  • 综上,具有 O(logn) 的时间复杂度。

空间复杂度

  • 递归版本的二分查找算法使用函数调用栈来存储递归调用的上下文。在最坏情况下,递归调用会达到 O(log n) 的深度,因此空间复杂度也为 O(log n)。这意味着在非常大的数据集上,可能会占用相对较多的内存。
  • 与递归版本相比,非递归版本的空间复杂度更低。它不需要函数调用栈来存储递归上下文,因此空间复杂度是 O(1),即常数级别的内存开销。
  • 综上,非递归的空间开销更小,空间复杂度是 O(1)。

稳定性

二分查找是稳定的,即在相同数组中查找相同元素时,始终返回相同的结果。

适用性

  • 递归版本的二分查找适用于有序数组中查找元素的场景。由于它需要递归调用,对于非递归版本可能会有稍微更高的内存开销,因此在特定内存受限或追求最大性能的情况下,迭代版本可能更受欢迎。
  • 非递归版本的二分查找通常更受欢迎,因为它在大多数编程语言中不会导致栈溢出的问题。此外,它的空间开销更小,因此适用于内存受限的环境和对性能要求较高的应用。

算法总结

总的来说,递归版本的二分查找是一种高效、简洁的查找算法,特别适用于有序数组的情况。但在某些编程语言中,递归调用可能会导致栈溢出,因此在这种情况下可能需要谨慎使用或选择迭代版本。非递归版本的二分查找是一种高效、稳定且经常使用的查找算法。在绝大多数情况下,它是首选的二分查找实现。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值