【趣学算法】Day4 分治算法——二分搜索

简介: 【趣学算法】Day4 分治算法——二分搜索

引入


现实生活中也有很多这样的例子,例如唱歌比赛,如果全国各地的歌手都来报名参赛,那么比赛就需要很长的时间,那怎么办呢?首先全国分赛区海选,然后每个赛区的前几名参加二分“海选”,最后选出比较优秀的选手参加电视节目比赛。这样既能把优秀的歌手呈现给观众,又能节省很多时间,因为全国各地分赛区的“海选”是同步进行的,有点“并行”的意思。


       在算法设计中,也可以引入分而治之的策略,称为分治算法。分治算法的本质就是将一个大规模的问题分解为若干规模较小的子问题,分而治之。


分治算法要素

(1)原问题可分解为若干规模较小的相同子问题。

(2)子问题相互独立。

(3)子问题的解可以合并为原问题的解。

分治算法秘籍


(1)分解:将想要解决的问题分解为若干规模较小、相互独立、与原问题形式相同的子问题。


(2)治理:求解各个子问题。由于各个子问题与原问题形式相同,知识规模较小而已,因此当子问题划分的足够小时,就可以使用较简单的方法来解决。


(3)合并:按原问题的要求,将子问题的解逐层合并,构成原问题的解。


二分搜索

算法题目

       某大型娱乐节目在玩猜数字游戏:主持人在女嘉宾的手心写一个10以内的整数,让女嘉宾的老公猜主持人写的数字是几,女嘉宾只能提示大了或小了,并且只有3次机会。


问题分析

       从问题描述看,如果是n个数,那么最坏的情况需要猜分搜索n次才能成功。其实完全没必要一个数一个数地猜,因为这些数是有序的。可以使用二分搜索策略,每次和中间的元素做比较。如果比中间元素小,就在前半部分查找;如果比中间元间素大,就在后半部分查找。


算法步骤

       一维 数组S[ ]用于存储有序序列,变量low 和high分别表示查找范围的下界和上界,middle 表示查找范围的中间位置,x为特定的查找元素。


(1)初始化。令low=0、high=n-1, 分别指向有序数组S[ ]中的第一个元素和最后一个元素。


(2) middle=(low+high)/2, 指向查找范围的中间元素。


(3) 如果low ≤ high, 转向步骤(4), 否则算法结束。


(4)如果 x = S[middle] , 则查找成功,算法结束。如果x > S[middle] , 则令low = middle + 1;否则令 high = middle - 1,转向步骤(2)。


完美图解

       在有序序列 (5,8. 15, 17. 25, 30. 34, 39, 45,52, 60) 中查找元素17的详细过程如下。

(1) 确定合适的数据结构。用一维数组S[ ]存储该有序序列,x = 17, 如下图所示。


a9cc7199c9104fde9602fc56d0b1a397.png

(2) 初始化。令low = 0、high = 10, 计算 middle=(low+high)/2=5 , 如下图所示。


250aab7082db432b9a87bd02d4a9e724.png

(3) 将 x 与 S[middle] 做比较。S[middle] = 30, x<S[middle],令high = middle-1,在序列的前半部分查找,搜索范围缩小到子问题S[0..middle-1] , 如下图所示。

ea374c257a4d42299240fc8bd946fac8.png

(4) 计算 middle = (low+high) / 2 = 2,如下图所示。

b9990a83538941c8bd528571cfba8382.png

(5) 将x 与 S[middle]做比较。S[middle]=15, x>S[middle], 令low = middle+1,在序列的后半部分查找,搜索范围缩小到子问题S[midde] +1..high],如下图所示。

cf3a3b435986494b8f7307bf8cc554ac.png


(6) 计算 midde=(low+high)/2=3,如下图所示。

8afc86525cd9471280992c3c8a1fdefa.png

(7)将 x 与 S[middle]做比较。x = S[middle] = 17,查找成功,算法结束。


算法详解


   下面使用BinarySearch(int s[ ] , int n , int x)函数实现二分搜索,其中s[ ]为有序数组,n为元素个数,x 为特定的查找元素。首先,令low指向有序数组的第一个元素,同时令high 指向有序数组的最后一个元素。如果 low <= high,则令 middle = (low + high) / 2,也就是令 middle 指向查找范围的中间元素。如果x = S[middle],则查找成功,返回元素的下标。如果x > S[middle],则令low = middle+1,在后半部分搜索;否则令high = middle -1, 在前半部分搜索。

       一般情况下,如果low和high的数值不大,可以采用 middle=(low+high)/2 或者 middle = (low + high) >> 1。如果low和high的数值特别大,为避免low+high溢出,可以采用 middle = low+(high-low)/2。


int BinarySearch(int s[], int n, int x) { //二分搜索
    int low = 0, high = n - 1;
    //low 指向有序数组的第一个元素,high 指向有序数组的最后一个元素
    while(low <= high) {
        int middle = (low + high) / 2;
        //middle 指向查找范围的中间元素
        if(x == s[middle]) { //查找成功
            return middle;
        } else if(x > s[middle]) { 
            //x 大于中间元素,在前半部分查找
            low = middle + 1;
            } else {
                //x 小于中间元素,在后半部分查找
                high = middle - 1;
            }
    }
    return -1;
}

算法分析


(1)时间复杂度:


 sort 排序函数的时间复杂度为 O(nlogn),如果数列本身有序,那么这部分不用考虑。二分查找算法的时间复杂的怎么计算呢?如果用 T(n) 表示 n 个有序元素的二分查找算法的时间复杂度,那么


       1)当 n = 1 时,需要进行一次比较,T(n) = O(1)。


       2)当 n > 1 时,需要将特定元素和中间元素做比较,时间复杂度为 O(1)。如果比较不成功,则需要在前半部分或后半部分查找,问题的规模缩小了一半,时间复杂度变为 T(n / 2)。


当 n = 1 时,T(n) = O(1);当 n > 1 时,T(n) = T(n / 2) + O(1)。


       3)当 n > 1 时,可以进行递归求解。


       T(n) = T(n / 2) + O(1)


               = T(n / 2 * 2) + 2O(1)


               = T(n / 2 * 2 * 2) + 3O(1)


               =……


               = T(n / 2 的x次方) + xO(1)


递归最终的数据规模为1,也就是说,n / 2 的x次方 = 1。由于 n = 2 的x次方,因此 x = logn。


二分查找算法的时间复杂度为O(logn)


(2)空间复杂度:

       辅助空间是一些变量,它们是常数阶的,因此空间复杂度为O(1)。


相关文章
|
3月前
|
算法
【算法】二分算法——搜索插入位置
【算法】二分算法——搜索插入位置
|
4月前
|
算法 开发者 Python
惊呆了!Python算法设计与分析,分治法、贪心、动态规划...这些你都会了吗?不会?那还不快来学!
【7月更文挑战第10天】探索编程巅峰,算法至关重要。Python以其易读性成为学习算法的首选。分治法,如归并排序,将大问题拆解;贪心算法,如找零问题,每步求局部最优;动态规划,如斐波那契数列,利用子问题解。通过示例代码,理解并掌握这些算法,提升编程技能,面对挑战更加从容。动手实践,体验算法的神奇力量吧!
72 8
|
8天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
25 2
|
12天前
|
算法 搜索推荐 数据库
二分搜索:高效的查找算法
【10月更文挑战第29天】通过对二分搜索的深入研究和应用,我们可以不断挖掘其潜力,为各种复杂问题提供高效的解决方案。相信在未来的科技发展中,二分搜索将继续发挥着重要的作用,为我们的生活和工作带来更多的便利和创新。
19 1
|
1月前
|
算法 决策智能
基于禁忌搜索算法的VRP问题求解matlab仿真,带GUI界面,可设置参数
该程序基于禁忌搜索算法求解车辆路径问题(VRP),使用MATLAB2022a版本实现,并带有GUI界面。用户可通过界面设置参数并查看结果。禁忌搜索算法通过迭代改进当前解,并利用记忆机制避免陷入局部最优。程序包含初始化、定义邻域结构、设置禁忌列表等步骤,最终输出最优路径和相关数据图表。
|
2月前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
54 2
|
1月前
|
存储 算法 C++
【搜索算法】 跳马问题(C/C++)
【搜索算法】 跳马问题(C/C++)
|
1月前
|
人工智能 算法 Java
【搜索算法】数字游戏(C/C++)
【搜索算法】数字游戏(C/C++)
|
3月前
|
机器学习/深度学习 算法 文件存储
【博士每天一篇文献-算法】 PNN网络启发的神经网络结构搜索算法Progressive neural architecture search
本文提出了一种名为渐进式神经架构搜索(Progressive Neural Architecture Search, PNAS)的方法,它使用顺序模型优化策略和替代模型来逐步搜索并优化卷积神经网络结构,从而提高了搜索效率并减少了训练成本。
55 9
|
3月前
|
算法
【算法】递归、搜索与回溯——汉诺塔
【算法】递归、搜索与回溯——汉诺塔