二分查找算法

本文深入探讨了算法的概念,强调了其有限性、确定性和可行性。数据结构被誉为“内功心法”,算法则为“武学招式”。重点讲述了算法效率的度量,包括事后统计方法和事前分析估算方法,以及如何通过大O记法描述算法的时间复杂度。介绍了顺序查找和二分查找两种查找算法,分析了它们的性能和适用条件,指出在评估算法优劣时应优先考虑时间复杂度,其次是空间复杂度。
摘要由CSDN通过智能技术生成

算法简介

  • 算法:描述解决问题的方法称之为算法

  • 定义:算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作
    在这里插入图片描述
    注意:
    1.同一个问题可能会有很多种不同的算法
    2.没有通用的算法能解决所有问题

  • 特性
    有穷性
    确定性
    可行性

  • 数据结构与算法的关系
    数据结构是“内功心法”
    算法是“武学招式”

  • 算法设计的要求
    在这里插入图片描述

算法效率的度量

  • 事后统计方法

    通过设计好的测试程序和数据,利用计算机计时器对不同算法编制的程序运行时间进行比较,从而确定算法效率的高低

    缺陷:
    1.必须依据算法编制好程序,这需要花费大量的实践和精力
    2.时间必须依赖计算机硬件和软件等环境因素,有时会掩盖算法本身的优劣
    3.算法的测试数据设计困难,并且程序的运行时间往往还与测试数据的规模有很大关系

  • 事前分析估算方法

    • 在计算机程序编制前,依据统计方法对算法进行估算

      不关心编写程序所用的程序设计语言是什么。也不关心这些程序将跑在什么样的计算机中,我们只关心它所实现的算法

    • 决定计算机程序运行时间的因素

      算法采用的策略、方法
      编译产生的代码质量(软件支持)
      问题的输入规模:指输入量的多少
      机器执行指令的速度

    • 在分析程序的运行时间时,最重要的是把程序看成是独立于程序设计语言的算法或一系列步骤
      在这里插入图片描述

函数的渐进增长

  • 函数渐进增长:

    给定两个函数f(n)和g(n),如果存在一个整数N,使得对于所有的n>N,f(n)总是比g(n)大,那么,我们说f(n)的增长渐进快于g(n)

  • 判断两个算法A和B的效率
    在这里插入图片描述

    在这里插入图片描述
    观察发现:
    1.最高次项的相乘的常数并不重要
    2.函数随着n的增长,最高次项的指数越大,结果也会变得增长特别快

    • 结论:
      判断一个算法的效率时,函数中的常数和其他次要项常常可以忽略,而更应该关注最高阶项的阶数

算法的时间复杂度

  • 定义:

    算法的时间复杂度就是算法的时间度量,记作:T(n) = O(f(n))
    T(n)表示语句总的执行次数,它是关于问题规模n的函数
    用O()来体现算法时间复杂度的记法,我们称之为大O记法

  • 推导大O阶次的方法

    用常数1取代运行时间中的所有加法常数
    在修改后的运行次数函数中,只保留最高阶项
    如果最高阶存在且不是1,则去除与这个项相乘的常数
    在这里插入图片描述

  • 常数阶的时间复杂度记为O(1)
    在这里插入图片描述

  • 线性阶的时间复杂度均为O(n) 在这里插入图片描述

  • 平方阶时间复杂度为O(n2)
    在这里插入图片描述

  • 对数阶时间复杂度O(log n)
    在这里插入图片描述

  • 常见的时间复杂度
    在这里插入图片描述

算法的空间复杂度

  • 算法的空间复杂度通过计算算法所需的存储空间实现

  • 算法的空间复杂度的计算公式记作:S(n) = O(f(n)),其中n为问题的规模,f(n)为语句关于n所占存储空间的函数

    • 如果算法执行时所需空间相对于输入数据量而言是个常数,则称此算法为原地工作,空间复杂度为O(1)
  • 算法优劣判定的基本原则
    优先判断时间复杂度的优劣
    时间复杂度相同,再判断空间复杂度的优劣

数据结构知识图谱

在这里插入图片描述

查找

  • 查找就是根据给定的某个值,在查找表中确定一个其关键字等于给定值得数据元素

  • 查找的基本概念
    在这里插入图片描述

  • 查找算法的评价指标
    在这里插入图片描述

顺序查找算法

  • 应用范围

    顺序表或线性链表表示的静态查找表

    表内元素之间无序

  • 顺序表的表示

    typedef struct{
        ElemType * R;       //表基址(顺序表的起始地址)
        int length;         //表长
    }SSTable;
    
  • 顺序查找算法描述

    int locateElem(Sqlist L, ElemType e)
    {
        for(int i = 0; i < L.length; i++)
        {
            if(L.elem[i] == e)
                return i;
        }
        return 0;
    }
    
  • 顺序查找算法改进算法
    在这里插入图片描述
    原算法中,for循环里有一次判断,for循环体内还会有一次判断
    改进算法中,只需要判断key值是否相等就可以,省了for循环次数的判断

    /** 改进后的代码 */
    int locateElem(SqList L,  ElemType e)
    {
    	//把第一个位置设置为哨兵
    	L.elem[0].data = e;
    	int i;
    	for(i = L.length; L.elem[i].data != e; i--);
    	return i;
    }
    

顺序查找的性能分析

  • 时间复杂度

    • 查找成功时的平均查找长度,设表中各记录查找概率相等:ASLS(n) = (1+2+…+n) / n = (n+1) / 2
    • 查找不成功时的平均查找长度:ASLf= n + 1
  • 空间复杂度

    • 一个辅助空间

有序表(二分)查找

  • 有序表查找的放法被称作折半查找,又叫二分法

  • 应用范围

    • 线性表中的记录是有序的,一般按照从小到大的顺序排列
  • 基本思想

    • 在有序表中,取中间值和要查找的值比较
    • 若等于中间值,则中间值即为要查找的
    • 若小于中间值,则中间值得左半区域继续查找
    • 若大于中间值,则中间值得右半区域继续查找
    • 不断重复上述过程

    设表长为n、low、high和mid分别指向待查元素所在区间的上界、下界和中点,k为给定值。
    初始时,令 low = 1, high = n, mid=【(low + high) / 2】(【】取整)

二分查找原理

  • 查找成功
    在这里插入图片描述

  • 查找失败
    在这里插入图片描述

  • 二分查找非递归算法描述

    /** 使用二分查找法返回关键字所在的位置(从1开始,没找到就返回0) */
    int SearchSeqListBinary(SeqList seqList, KeyType key)
    {
        int low = 1;
        int high = seqList.length;
    
        //二分查找法的前提:必须有序,从小到大升序。
        while(low <= high)
        {
            int mid = (low + high) / 2;
            if(key == seqList.datas[mid].key)
            {
                return mid;
            }
            else if(key < seqList.datas[mid].key)
            {
                high = mid - 1;
            }
            else
            {
                low = mid + 1;
            }
        }
        return 0;
    }
    
  • 二分查找递归算法描述

    /** 使用递归实现的二分查找法返回关键字所在的位置(从1开始,没找到就返回0) */
    int SearchSeqListBinaryRecursion(SeqList seqList, KeyType key, int low, int high)
    {
       while(low > high)    return 0;
       int mid = (low + high) / 2;
       if(key == seqList.datas[mid].key)    return mid;
       else if(key < seqList.datas[mid].key)
       {
           return SearchSeqListBinaryRecursion(seqList, key, low, mid - 1);
       }
       else
       {
           return SearchSeqListBinaryRecursion(seqList, key, mid + 1, high);
       }
       return 0;
    }
    

二分查找的性能分析

  • 查找过程

    • 比较次数少,查找效率高(每次将待查记录所在区间缩小一半,比顺序查找效率高);
    • 时间复杂度 O ( l o g 2 n ) O(log_2n) O(log2n)
  • 使用条件

    • 采用顺序存储结构的有序表
    • 不适用于元素经常变动的线性表
    • 不宜用于链式结构

二叉排序树(BinarySortTree)

  • 树表的查找:表结构在查找过程中动态生成

  • 查找:

    • 对于给定值key
    • 若表中存在,则成功返回
    • 否则插入关键字等于key的记录
  • 二叉排序树(BinarySortTree):又称为二叉查找树(BinarySearchTree),也称为二叉搜索树

    二叉树排序树是一棵空树或是满足如下性质的二叉树:

    • 若其左子树非空,则左子树上所有结点的值均小于根节点的值;
    • 若其右子树非空,则右子树上所有结点的值均大于等于根节点的值;
    • 其左右子树本身又各是一棵二叉排序树

    在这里插入图片描述

  • 中序遍历二叉排序树
    在这里插入图片描述

二叉排序树的查找

  • 二叉查找原理
    在这里插入图片描述
  • 二叉排序树查找算法描述
    在这里插入图片描述
  • 二叉排序树的插入算法描述
    在这里插入图片描述

二叉排序树查找的性能分析

在这里插入图片描述
第i层结点需要比较i次
在等概率的前提下,两图的平均查找长度分别为:
左图 ∑ i = 1 n p i c i = ( 1 + 2 ∗ 2 + 3 ∗ 2 ) / 5 = 2.2 \sum_{i=1}^np_ic_i=(1+2*2+3*2) / 5 = 2.2 i=1npici=(1+22+32)/5=2.2
右图 ∑ i = 1 n p i c i = ( 1 + 2 + 3 + 4 + 5 ) / 5 = 3 \sum_{i=1}^np_ic_i = (1+2+3+4+5) / 5 = 3 i=1npici=(1+2+3+4+5)/5=3
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值