【算法详解 | 二分查找】详解二分查找 \ 折半查找高效搜索算法 | 顺序数组最快搜索算法 | 递归&循环解决二分查找问题

二分查找

by.Qin3Yu

本文需要读者掌握 顺序表 的操作基础,完整代码将在文章末尾展示。

顺序表相关操作可以参考我的往期博文:
【C++数据结构 | 顺序表速通】使用顺序表完成简单的成绩管理系统.by.Qin3Yu

文中所有代码使用 C++ 举例,且默认已使用部分头文件和 std 命名空间:

#include 
#include 
using namespace std;

概念速览

二分查找概述

  • 二分查找 算法属于 搜索算法 的一种。它是一种高效的搜索算法,用于在有序数组或列表中查找特定元素的位置。
  • 二分查找的基本思想是通过将目标值与数组中间的元素进行比较,从而将搜索范围缩小一半。如果目标值小于中间元素,则继续在左侧子数组中进行二分查找;如果目标值大于中间元素,则继续在右侧子数组中进行二分查找;如果目标值等于中间元素,则直接返回该位置。通过重复这个过程,最终可以找到目标值或确定其不存在于数组中。
  • 二分查找算法的时间复杂度为 O(log n) ,且不需要额外存储空间。

二分查找通常被使用于符合以下条件的以下场景:

  1. 数组或列表是 有序 的;
  2. 静态 数据结构;
  3. 数据量较
  4. 只需要 快速确定 元素是否存在。

算法详解

逻辑解析

  • 二分查找,就是不断的对搜索范围进行折半,从而缩小搜索范围,我们用下面的数组来进行说明:

在这里插入图片描述

  • 在上面的有序数组中,我们要查找数组内是否存在值 31 ,于是我们可以如下图所示,使用三个指针,一个指向数组的最左端,一个指向数组的最右端,一个指向数组的中间。

【算法详解 | 二分查找】详解二分查找 \ 折半查找高效搜索算法 | 顺序数组最快搜索算法 | 递归&循环解决二分查找问题_第1张图片

  • 我们使用 leftrightmid 分别表示左、右、中指针,当前 mid 指向的值为 26 ,因为数组是有序数组,所以可以得知,我们要查找的值 31 一定在 26右侧 ,因此,我们将左指针 left 指针指向 mid 的后一位元素,然后重新计算出 mid 指针的位置:

【算法详解 | 二分查找】详解二分查找 \ 折半查找高效搜索算法 | 顺序数组最快搜索算法 | 递归&循环解决二分查找问题_第2张图片

  • 如图所示,当前 mid 指向的值为 44 ,比 31 小,因此我们要查找的 31 一定在 44 的左侧,因此,我们把右指针 right 指向 mid 的前一位元素,然后重新计算 mid 的位置:

【算法详解 | 二分查找】详解二分查找 \ 折半查找高效搜索算法 | 顺序数组最快搜索算法 | 递归&循环解决二分查找问题_第3张图片

  • 同理,mid 指向的值 30 小于 31 ,所以我们把 left 移到 mid 的后一位,然后重新计算 mid 的位置:

【算法详解 | 二分查找】详解二分查找 \ 折半查找高效搜索算法 | 顺序数组最快搜索算法 | 递归&循环解决二分查找问题_第4张图片

注意:在二分查找中,rightleft 重合属于正常现象,表示搜索范围只有一个数字。

  • 此时,我们再检查 mid 所指的值,就是我们要查找的 31,于是我们返回出对应的结果,表示成功查找到元素。
  • 我们在上一步的例子中做出一点修改,假如数组中没有我们要查找的值 31 ,则会产生一种情况,即 left 跑到 right 的右边,代表数组中没有我们要查找的元素:

【算法详解 | 二分查找】详解二分查找 \ 折半查找高效搜索算法 | 顺序数组最快搜索算法 | 递归&循环解决二分查找问题_第5张图片

代码实现

  • 在下例中,我们使用 vector 顺序表来保存数据,然后使用 binarySearch 方法表示二分搜索:
int main() {
    vector<int> data = {1,7,9,11,14,19,20,26,29,30,31,44,45,52,59};
    int target = 31;
    int result = binarySearch(data, target);
}
  • 首先,我们要声明左右指针,左指针指向数组最前端,即索引为 [0] ,右指针指向数组最右端,即索引为 [长度-1]
int left = 0;
int right = arr.size() - 1;
  • 在上文中我们提到,如果 left 指针移动到了 right 指针右边,则代表数组内没有对应的值,则返回 -1 ,表示没有目标值:
while (left <= right) {
    ...
}
return -1;
  • 接下来,我们要根据左右指针计算出中间指针 mid ,即左指针加上两指针之和除二:
int mid = left + (right - left) / 2;
  • 最后,我们来判断 mid 指针所指值与查找值的关系,如果相等,则返回成功目标值的索引:
if (arr[mid] == target) {
    return mid;  // 找到目标,返回索引
}
  • 如果 mid 所指值比目标值小,则证明目标值只可能在 mid 右边,我们将 left 指针移到 mid 指针后一位,从右侧子数字开始查找:

【算法详解 | 二分查找】详解二分查找 \ 折半查找高效搜索算法 | 顺序数组最快搜索算法 | 递归&循环解决二分查找问题_第6张图片

else if (arr[mid] < target) {
    left = mid + 1;  // 继续在右侧子数组中查找
}
  • 相反,如果 mid 所指值比目标值大,则证明目标值只可能在 mid 左边,我们将 right 指针移到 mid 指针前一位,从左侧子数字开始查找:

在这里插入图片描述

else {
    right = mid - 1;  // 继续在左侧子数组中查找
}
  • 将上述代码做出结合后,便是完整的二分查找代码,具体如下文所示。

完整算法代码

#include 
#include 
using namespace std;

int binarySearch(const vector<int>& arr, int target) {
    int left = 0;
    int right = arr.size() - 1;

    while (left <= right) {
        int mid = left + (right - left) / 2;  // 防止(left + right)出现溢出

        if (arr[mid] == target) {
            return mid;  // 找到目标,返回索引
        } else if (arr[mid] < target) {
            left = mid + 1;  // 继续在右侧子数组中查找
        } else {
            right = mid - 1;  // 继续在左侧子数组中查找
        }
    }

    return -1;  // 没有找到目标,返回-1
}

int main() {
    vector<int> data = {1,7,9,11,14,19,20,26,29,30,31,44,45,52,59};
    int target = 31;
    int result = binarySearch(data, target);

    if (result != -1) {55
        cout << "成功查找到对应值!" << result << endl;
    } else {
        cout << "找不到对应值。" << endl;
    }

    return 0;
}

至此,二分查找的所有内容讲解完毕(=
感谢您的阅读(=
CSDN.by.Qin3Yu

你可能感兴趣的:(算法详解,算法,查找,二分查找,搜索,二分,数据结构,C++)