前言

上一篇在聊时间复杂度和空间复杂度时,没有按指定格式显示(明明预览的时候没问题的),强迫症的我稍微优化了一下重新发布,目的就是让小伙伴看着舒服。

上次聊到的直接插入排序在比较有序数据和待插入数据时,是通过依次遍历的方式进行比较,当数据量比较大时,得考虑进一步优化;折半插入排序就是通过减少有序数据与待插入数据的比较次数,从而提升效率。

正文

1. 先来熟悉一下折半查找

1.1  折半查找算法思想

折半查找又称二分查找,仅适用于有序的顺序表

思想(假设顺序表是升序的):

  • 首先将指定值与顺序表中中间位置元素进行比较;

  • 若相等,代表找到,则返回该元素的位置;

  • 若不等,需继续查找;

    若指定的值小于顺序表中中间元素,则查找前半部分;

    若指定的值大于顺序表中中间元素,则查找后半部分;

重复以上过程,直到找到元素为止;或者找完所有数据为止,即查找失败;

1.2 折半查找实现及解析

算法代码如下(在升序顺序表中查数据)

image-20210327174929319

执行结果如下:

image-20210327175057909

解析查找步骤过程,如下:

图中分别使用红、绿、黄箭头所指的数据分别高、中、低索引位,蓝色为需要在顺序表中查找的数。

能查到数据的步骤:

image-20210328000114746

上图步骤说明:

  • 第1步将low初始为0,high初始赋值为顺序表中的元素个数减1,这里为5;当循环进来时将mid赋值为(low+high)/2,因为mid为int类型,会取整,这里就得到mid为2;然后将索引位为2的数据66与需要查找的数据92进行比较,发现92大于66,需继续在后半部分查找,所以将low的值改为mid+1,即为3;

  • 第2步进入循环,继续将mid的赋值为(low+high)/2,因为上一步low的值为3,high的值不变,还是为5,所以得出的mid值为4,然后将索引位为4的数据92与需要查找的数据92进行比较,两者相等,代表已经找到,返回当时找到的位置mid。

查找失败时的情况:

image-20210328000247255

上图步骤说明:

  • 第1步将low初始为0,high初始赋值为顺序表中的元素个数减1,这里为5;当循环进来时将mid赋值为(low+high)/2,因为mid为int类型,会取整,这里就得到mid为2;然后将索引位为2的数据66与需要查找的数据921进行比较,发现921大于66,需继续在后半部分查找,所以将low的值改为mid+1,即为3;

  • 第2步进入循环,继续将mid的赋值为(low+high)/2,因为上一步low的值为3,high的值不变,还是为5,所以得出的mid值为4,然后将索引位为4的数据92与需要查找的数据921进行比较,发现921大于92,需继续在后半部分查找,所以将low的值改为mid+1,即为5;

  • 第3步进入循环,继续将mid的赋值为(low+high)/2,因为上一步low的值为5,high的值不变,还是为5,所以得出的mid值为5(这里高、中、低都指向同一位置),然后将索引位为5的数据100与需要查找的数据921进行比较,发现921大于100,需继续在后半部分查找,所以将low的值改为mid+1,即为6;

  • 第4步进入循环时,low在第3步时变为6,high还是没变,依然是5,low大于high,不满足循环条件,代表已经查询完成,但没有查询到数据,跳出循环,返回-1;

1.3 分析折半查找算法性能

时间复杂度

如果传入的数据规模为n,即有n个元素;第一次在 n/2个元素中查找,第二次在n/(22)个元素中查找,第三次在n/(23)个元素中查找,假如经过x次查找到元素,则得到时间复杂度为O(log2n);

空间复杂度

因为在查找过程中,用到了固定的几个中间变量(low,mid,high),所以算法过程中消耗的内存是一个常量级别的,则空间复杂度为O(1);

稳定性

由于在算法过程中只是查找,不改变元素的位置,则折半查找算法是稳定的。

综上所述,插入排序的时间复杂度为O(log2n),空间复杂度为O(1),是稳定算法;

2. 搞明白折半插入排序

2.1 折半插入排序算法思想

折半插入排序是对直接插入排序的优化,直接插入排序在比较过程中依次遍历有序列表中的元素和待插入数据比较,而折半插入排序是将原来的依次遍历有序列表换成折半查找算法,提升比较效率,找到合适位置之后,对应的元素需要向后移位,然后将待插入元素插入到腾出的空位即可;重复到排序完成为止。

2.2 折半插入排序算法实现与解析

代码实现(升序):

image-20210329104257982

运行效果如下:

image-20210329104425770

步骤解析如图:

image-20210329123521476

步骤说明:

图中绿线框部分代表是已经排好序的列表,箭头指的元素是下一个待插入的元素,黄线框部分为剩下的无序元素。黄方块为每次折半查找到的mid位置,绿方块表示最后有序列表腾出的位置。

  • 将原始数据array复制到新数组中arrayb中,这步的主要目的是后续不需要声明额外临时变量,也为了后续核心代码实现逻辑简单易懂,减少过多的判断;

  • 第1步将第一个元素作为有序列表(第一元素为2),下一个待插入的元素为5,将5放入哨兵位置,即索引为0的位置;然后折半查找,初始low为1,high为第一次也为1;因为刚开始有序列表中只有一个元素,则找到就是2,与哨兵位的值5比较,2小于5,需要继续在有序列表的后半部分查找,改变low为mid+1,此时为2,大于high,跳出循环;不需要移动位置,保持当前位置不变。

  • 第2步时,有序列表中的元素为2、5,下一个待插入的元素为6,将6放入哨兵位置,即索引为0的位置;然后折半查找:

    第2-1步 初始low为1,此时计算出high的值为2;根据low和high计算出mid为1(因为是mid是整数,所以3除以2,取整为1),将mid位的值2与待插入元素6比较,2小于6,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid加1,得到low为2;

    第2-1步 上一步得到low为2,high的值仍然为2;根据low和high计算出mid为2,将mid位的值5与待插入元素6比较,5小于6,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid加1,得到low为3;不满足循环条件,退出折半;不需要移动位置,保持当前位置不变;

  • 第3步时,有序列表中的元素为2、5、6,下一个待插入的元素为1,将1放入哨兵位置,即索引为0的位置;然后折半查找:

    第3-1步 初始low为1,此时计算出high的值为3;根据low和high计算出mid为2,将mid位的值5与待插入元素1比较,5大于1,需要继续在有序列表中的前半部分继续查找,则改变high的值,为mid减1,得到high为1;

    第3-2步 初始low为1,上一步计算出high的值为1;根据low和high计算出mid为1,将mid位的值2与待插入元素1比较,2大于1,需要继续在有序列表中的前半部分继续查找,则改变high的值,为mid减1,得到high为0;继续循环是low大于high,不满足条件,跳出循环;

    第3-3步 根据折半查找比较,得出合适位置为high+1,即需要将待插入元素插入到1位置,需要将2、5、6三个元素依次向后移位,腾出索引位1的位置,将待插入元素1插入到此索引位。

  • 第4步时,有序列表中的元素为1、2、5、6,下一个待插入的元素为9,将9放入哨兵位置,即索引为0的位置;然后折半查找:

    第4-1步 初始low为1,此时计算出high的值为4;根据low和high计算出mid为2(因为是mid是整数,所以5除以2,取整为2),将mid位的值2与待插入元素9比较,2小于9,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid+1,得到low为3;

    第4-2步 上一步计算出low为3,high的值仍然为4;根据low和high计算出mid为3(因为是mid是整数,所以7除以2,取整为3),将mid位的值5与待插入元素9比较,5小于9,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid+1,得到low为4;

    第4-3步 上一步计算出low为4,high的值仍然为4;根据low和high计算出mid为4,将mid位的值6与待插入元素9比较,6小于9,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid+1,得到low为5;继续循环是low大于high,不满足条件,跳出循环;

  • 第5步是,有序列表中的元素为1、2、5、6、9,下一个待插入的元素为3,将3放入哨兵位置,即索引为0的位置;然后折半查找:

    第5-1步 初始low为1,此时计算出high的值为5;根据low和high计算出mid为3,将mid位的值5与待插入元素3比较,5大于3,需要继续在有序列表中的前半部分继续查找,则改变high的值,为mid减1,得到high为2;

    第5-2步 初始low为1,上一步计算出high的值为2;根据low和high计算出mid为1(3除以2取整得1),将mid位的值1与待插入元素3比较,1小于3,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid加1,得到low为2;

    第5-3步,上一步计算出low为2,第5-1步计算出high为2;根据low和high计算出mid为2,将mid位的值2与待插入元素3比较,2小于3,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid加1,得到low为3;继续循环,不符合循环条件,循环终止

    第5-4步 根据折半查找比较,得出合适位置为high+1,即需要将待插入元素插入到3位置,需要将5、6、9三个元素依次向后移位,腾出索引位3的位置,将待插入元素3插入到此索引位。最终得到排序结果1、2、3 、5 、6 、9;

2.3 折半插入排序算法分析

时间复杂度

在算法过程中有两层循环,第一层需要遍历所有元素,则时间复杂度为O(n);第二层循环中包含两部分算法,第一步是通过折半算法找位置,时间复杂度在刚开始已经分析,为O(log2n);第二步是找到位置之后需要腾出空位,需要将对应元素移位,时间复杂度为O(n);则整体算法的时间复杂度为外层循环的时间复杂度乘以内层循环的时间复杂度,去掉系数和常数,取大的,得出结果为O(n2);

空间复杂度

在算法核心部分只采用了固定的几个中间变量(i,j,low,mid,high,arrayb[0]),所以算法过程中消耗的内存是一个常量,则空间复杂度为O(1);

稳定性

由于在算法过程中采用折半算法找位置的,使用大于符号进行比较值,所以当遇到相等数据时,位置不会受到改变,则折半插入算法是稳定的。

综上所述,折半插入排序的时间复杂度为O(n2),空间复杂度为O(1),是稳定算法;

总结

这里说到两种算法,折半查找(二分查找)算法,折半插入排序算法;最终关于插入排序算法的思想没变,只是在比较有序列表时做了优化;对于小数据量的排序,感觉不到优化,当数据量大时,比较效率就明显提升啦;如果不明白的小伙伴调试代码试试,再不行可以留言,有时间会及时回复。

感谢小伙伴的:点赞收藏评论,下期继续~~~

一个被程序搞丑的帅小伙,关注"Code综艺圈",跟我一起学~~~

二分查找和折半插入排序一块说说-很合适~~~相关推荐

  1. 插入排序一块说说-很合适~~~二分查找和折半

    . 先来熟悉一下折半查找 1.1 折半查找算法思想 折半查找又称二分查找,仅适用于有序的顺序表: 思想(假设顺序表是升序的): 首先将指定值与顺序表中中间位置元素进行比较: 若相等,代表找到,则返回该 ...

  2. 数据结构之二分查找(折半查找)

    数据结构之二分查找(折半查找) 二分查找又称折半查找,优点是次数比较少,查找速度快,平均性能好,其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表.首先 ...

  3. 二分查找的平均查找长度_二分查找(折半查找)代码实现

    整理不易,手有余香请点赞! 折半查找,也称二分查找,在某些情况下相比于顺序查找,使用折半查找算法的效率更高.但是该算法的使用的前提是静态查找表中的数据必须是有序的. 在折半查找之前对查找表按照所查的关 ...

  4. 二分查找(折半查找)简介与代码实现(C++)

    二分查找(折半查找)简介与代码实现 1.简介 2.代码实现(C++) 2.1.写法一(target在左闭右闭区间) 2.2.写法二(target在左闭右开区间) 3.代码检验 1.简介 二分查找的本质 ...

  5. 二分查找(折半查找)总结

    ** 二分查找(折半查找)总结 ** 文章目录 二分查找(折半查找)总结 一.基本概念 二.编写代码 1.二分查找 2.测试代码 三.输出结果 四.总结评价 一.基本概念 二分查找也叫折半查找,是一种 ...

  6. python实现二分查找(折半查找)算法

    python实现二分查找算法 二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法.但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列. 查找又称折半 ...

  7. 二分查找(折半查找)详解

    二分查找详解 1. 二分查找的引入 2. 二分的一些基本知识 1) 定义 2) 特点 3. 二分查找的边界问题 1) 常用模板 2)综合练习 4.二分的应用 1) Flyer 2) Distribut ...

  8. 详解【C语言】中的二分查找法和折半查找法(例题解答)

    目录 问题 思路 详解 代码 问题 在一个有序数组中查找具体的某个数字n 比如我买了一双鞋,你好奇问我多少钱,我说不超过300元.你还是好奇,你想知道到底多少,我就让你猜,你会怎么猜? 答案:你每次猜 ...

  9. 数据结构50:二分查找法(折半查找法)

    折半查找,也称二分查找,在某些情况下相比于顺序查找,使用折半查找算法的效率更高.但是该算法的使用的前提是静态查找表中的数据必须是有序的. 例如,在{5,21,13,19,37,75,56,64,88 ...

最新文章

  1. spring整合redis缓存
  2. 云计算(Cloud Computing)的前世今生
  3. **16.app后端如何保证通讯安全--url签名
  4. Java生鲜电商平台-订单配送模块的架构与设计
  5. 额,你在main.xml中加了一个id以后,要右键点save,才会将这个id加入到R中,否则是没有的。。。R里的东西是程序自动生成的~~~...
  6. dynamo python修改多个参数_python之函数
  7. 获取本机IP(考虑多块网卡、虚拟机等复杂情况)
  8. 计算机专业中专排名,江西计算机专业学校排名中专
  9. 设置自定义ASP.NET服务器控件TagPrefix的几种方法
  10. 一些同样适用于人生的计算机原理
  11. 主题背景_游戏背景音乐的种类—主题曲
  12. Atitit 颜色平均值cloor grb hsv模式的区别对比
  13. mysql 练习题网站_mysql练习题
  14. yjj某数后缀生成(1-15,js逆向)
  15. Java打包后运行找不到资源文件问题
  16. 安卓10源码添加系统服务后配置SeLinux让其拥有Sdcard读写权限
  17. ChatGPT 使用 拓展资料:使用 HuggingFace+Gradio 部署快速搭建一个ChatGPT的聊天界面
  18. Fortofy扫描漏洞解决方案
  19. 获取并显示服务器数据,客户端获取服务器数据解析
  20. 笃定“凡勃仑效应”?索尼可能想错了

热门文章

  1. highgui java opencv_java – OpenCV 3.0.0 JAR缺少HighGUI
  2. cf769D(枚举位或运算)
  3. [C/C++]重读《The C Programming Language》
  4. 同步您的Google Chrome书签,主题等
  5. 爱普生第三方相机_值得购买第三方相机镜头吗?
  6. JavaScript-client、offset、scroll、定时器
  7. Redis 通配符批量删除key
  8. 【tomcat】servlet原理及其生命周期
  9. 从零开始编写自己的C#框架(14)——T4模板在逻辑层中的应用(三)
  10. oracle导出数据库中表出现导出报错(EXP-00003)未找到段 (0,0) 的存储定义